瀏覽代碼

Add a 3D physical light and camera units demo

Hugo Locurcio 2 年之前
父節點
當前提交
d4496aada8

+ 1 - 0
.gitignore

@@ -20,3 +20,4 @@ mono_crash.*.json
 .directory
 .DS_Store
 *~
+*.blend1

+ 25 - 0
3d/physical_light_camera_units/README.md

@@ -0,0 +1,25 @@
+# Physical Light and Camera Units
+
+This demo showcases a
+[physical light and camera units](https://docs.godotengine.org/en/latest/tutorials/3d/physical_light_and_camera_units.html)
+setup. This allows you to use real world units for lights (lumen, lux, Kelvin)
+and cameras (shutter speed, aperture, ISO sensitivity).
+
+By default, Godot uses arbitrary units for many physical properties that apply
+to light like color, energy, camera field of view, and exposure. These
+properties use arbitrary units, because using accurate physical units comes with
+a few tradeoffs that aren't worth it for many games. As Godot favors ease of use
+out of the box, physical light units are disabled by default.
+
+If you aim for photorealism in your project, using real world units as a basis
+can help make things easier to adjust. References for real world materials,
+lights and scene brightness are wildly available on websites such as
+[Physically Based](https://physicallybased.info/).
+
+Language: GDScript
+
+Renderer: Forward+
+
+## Screenshots
+
+![Screenshot](screenshots/physical_light_camera_units.webp)

二進制
3d/physical_light_camera_units/icon.webp


+ 34 - 0
3d/physical_light_camera_units/icon.webp.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bqj16te5ie2x5"
+path="res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.webp"
+dest_files=["res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.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

二進制
3d/physical_light_camera_units/living_room.blend


二進制
3d/physical_light_camera_units/living_room.glb


+ 32 - 0
3d/physical_light_camera_units/living_room.glb.import

@@ -0,0 +1,32 @@
+[remap]
+
+importer="scene"
+importer_version=1
+type="PackedScene"
+uid="uid://doh0vqn8wpfky"
+path="res://.godot/imported/living_room.glb-e9e76bdaf4212fbe5bd6be0e778b81a5.scn"
+
+[deps]
+
+source_file="res://living_room.glb"
+dest_files=["res://.godot/imported/living_room.glb-e9e76bdaf4212fbe5bd6be0e778b81a5.scn"]
+
+[params]
+
+nodes/root_type="Node3D"
+nodes/root_name="Scene Root"
+nodes/apply_root_scale=true
+nodes/root_scale=1.0
+meshes/ensure_tangents=true
+meshes/generate_lods=false
+meshes/create_shadow_meshes=true
+meshes/light_baking=1
+meshes/lightmap_texel_size=0.03
+skins/use_named_skins=true
+animation/import=true
+animation/fps=30
+animation/trimming=false
+animation/remove_immutable_tracks=true
+import_script/path=""
+_subresources={}
+gltf/embedded_image_handling=1

+ 92 - 0
3d/physical_light_camera_units/options.gd

@@ -0,0 +1,92 @@
+extends Control
+
+@export var sun: DirectionalLight3D
+@export var lightbulb_1: OmniLight3D
+@export var lightbulb_2: OmniLight3D
+@export var world_environment: WorldEnvironment
+
+## Returns color from a given temperature in kelvins (6500K is nearly white).
+## Valid range is [1000; 15000].
+## As explained in the Filament documentation:
+## https://google.github.io/filament/Filament.md.html#lighting/directlighting/lightsparameterization
+##
+## This is the same function as used internally by the engine when setting a
+## Light3D's `light_temperature`, but converted to GDScript.
+func get_color_from_temperature(p_temperature: float) -> Color:
+	var t2 := p_temperature * p_temperature
+	var u := (
+			(0.860117757 + 1.54118254e-4 * p_temperature + 1.28641212e-7 * t2) /
+			(1.0 + 8.42420235e-4 * p_temperature + 7.08145163e-7 * t2)
+	)
+	var v := (
+			(0.317398726 + 4.22806245e-5 * p_temperature + 4.20481691e-8 * t2) /
+			(1.0 - 2.89741816e-5 * p_temperature + 1.61456053e-7 * t2)
+	)
+
+	# Convert to xyY space.
+	var d := 1.0 / (2.0 * u - 8.0 * v + 4.0)
+	var x := 3.0 * u * d
+	var y := 2.0 * v * d
+
+	# Convert to XYZ space.
+	var a := 1.0 / maxf(y, 1e-5)
+	var xyz := Vector3(x * a, 1.0, (1.0 - x - y) * a)
+
+	# Convert from XYZ to sRGB(linear).
+	var linear := Vector3(
+			3.2404542 * xyz.x - 1.5371385 * xyz.y - 0.4985314 * xyz.z,
+			-0.9692660 * xyz.x + 1.8760108 * xyz.y + 0.0415560 * xyz.z,
+			0.0556434 * xyz.x - 0.2040259 * xyz.y + 1.0572252 * xyz.z
+	)
+	linear /= maxf(1e-5, linear[linear.max_axis_index()])
+	# Normalize, clamp, and convert to sRGB.
+	return Color(linear.x, linear.y, linear.z).clamp().linear_to_srgb()
+
+
+func _on_time_of_day_value_changed(value: float) -> void:
+	var offset := TAU * 0.25
+	sun.rotation.x = remap(value, 0, 1440, 0 + offset, TAU + offset)
+	print(rad_to_deg(sun.rotation.x))
+
+	# Improve and prevent light leaks by hiding the sun if it's below the horizon.
+	const EPSILON = 0.0001
+	sun.visible = sun.rotation.x > TAU * 0.5 + EPSILON and sun.rotation.x < TAU - EPSILON
+
+	$Light/TimeOfDay/Value.text = "%02d:%02d" % [value / 60, fmod(value, 60)]
+
+
+func _on_sun_intensity_value_changed(value: float) -> void:
+	sun.light_intensity_lux = value
+	$Light/SunIntensity/Value.text = "%d lux" % value
+
+
+func _on_lightbulb1_intensity_value_changed(value: float) -> void:
+	lightbulb_1.light_intensity_lumens = value
+	$Light/Lightbulb1Intensity/Value.text = "%d lm" % value
+
+
+func _on_lightbulb1_temperature_value_changed(value: float) -> void:
+	lightbulb_1.light_temperature = value
+	print(lightbulb_1.light_color)
+	$Light/Lightbulb1Temperature/Value.text = "%d K" % value
+	$Light/Lightbulb1Temperature/Value.add_theme_color_override("font_color", get_color_from_temperature(value))
+
+
+func _on_lightbulb2_intensity_value_changed(value: float) -> void:
+	lightbulb_2.light_intensity_lumens = value
+	$Light/Lightbulb2Intensity/Value.text = "%d lm" % value
+
+
+func _on_lightbulb2_temperature_value_changed(value: float) -> void:
+	lightbulb_2.light_temperature = value
+	$Light/Lightbulb2Temperature/Value.text = "%d K" % value
+	$Light/Lightbulb2Temperature/Value.add_theme_color_override("font_color", get_color_from_temperature(value))
+
+
+func _on_autoexposure_speed_value_changed(value: float) -> void:
+	get_viewport().get_camera_3d().attributes.auto_exposure_speed = value
+	$Camera/AutoexposureSpeed/Value.text = "%.1f" % value
+
+
+func _on_sdfgi_button_toggled(button_pressed: bool) -> void:
+	world_environment.environment.sdfgi_enabled = button_pressed

+ 38 - 0
3d/physical_light_camera_units/project.godot

@@ -0,0 +1,38 @@
+; 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
+
+[application]
+
+config/name="Physical Light and Camera Units"
+config/description="This demo showcases a physical light and camera units setup.
+This allows you to use real world units for lights (lumen, lux, Kelvin)
+and cameras (shutter speed, aperture, ISO sensitivity)."
+run/main_scene="res://test.tscn"
+config/features=PackedStringArray("4.0")
+config/icon="res://icon.webp"
+
+[display]
+
+window/stretch/mode="canvas_items"
+window/stretch/aspect="expand"
+
+[filesystem]
+
+import/blender/enabled=false
+
+[rendering]
+
+lights_and_shadows/use_physical_light_units=true
+lights_and_shadows/directional_shadow/size=8192
+lights_and_shadows/directional_shadow/soft_shadow_filter_quality=3
+lights_and_shadows/positional_shadow/soft_shadow_filter_quality=3
+global_illumination/sdfgi/probe_ray_count=5
+anti_aliasing/quality/msaa_3d=2
+anti_aliasing/quality/use_debanding=true

+ 0 - 0
3d/physical_light_camera_units/screenshots/.gdignore


二進制
3d/physical_light_camera_units/screenshots/physical_light_camera_units.webp


+ 317 - 0
3d/physical_light_camera_units/test.tscn

@@ -0,0 +1,317 @@
+[gd_scene load_steps=8 format=3 uid="uid://c2wwh47i8o462"]
+
+[ext_resource type="PackedScene" uid="uid://doh0vqn8wpfky" path="res://living_room.glb" id="1_oncn7"]
+[ext_resource type="Script" path="res://options.gd" id="2_hjhvo"]
+
+[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_6cd1w"]
+use_debanding = false
+
+[sub_resource type="Sky" id="Sky_i7d6m"]
+sky_material = SubResource("PhysicalSkyMaterial_6cd1w")
+
+[sub_resource type="Environment" id="Environment_3p42x"]
+background_mode = 2
+sky = SubResource("Sky_i7d6m")
+tonemap_mode = 3
+tonemap_white = 6.0
+sdfgi_use_occlusion = true
+sdfgi_cascades = 2
+sdfgi_min_cell_size = 0.15
+sdfgi_cascade0_distance = 9.6
+sdfgi_max_distance = 38.4
+sdfgi_y_scale = 0
+glow_enabled = true
+
+[sub_resource type="CameraAttributesPhysical" id="CameraAttributesPhysical_n2bnf"]
+auto_exposure_enabled = true
+auto_exposure_speed = 1.0
+
+[sub_resource type="CameraAttributesPhysical" id="CameraAttributesPhysical_drxnu"]
+auto_exposure_enabled = true
+auto_exposure_speed = 1.0
+frustum_focal_length = 25.0
+
+[node name="Node3D" type="Node3D"]
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+environment = SubResource("Environment_3p42x")
+camera_attributes = SubResource("CameraAttributesPhysical_n2bnf")
+
+[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
+transform = Transform3D(-0.887673, -0.456539, 0.0600684, 0.273782, -0.418382, 0.866025, -0.370243, 0.785193, 0.496379, 0, 0, 0)
+light_angular_distance = 0.5
+light_bake_mode = 1
+shadow_enabled = true
+shadow_blur = 1.8
+directional_shadow_mode = 0
+directional_shadow_blend_splits = true
+directional_shadow_fade_start = 1.0
+directional_shadow_max_distance = 15.0
+
+[node name="Camera3D" type="Camera3D" parent="."]
+transform = Transform3D(-0.824458, 0.0252143, -0.565361, 0, 0.999007, 0.0445544, 0.565923, 0.0367332, -0.82364, -2.93199, 2.20651, -1.8947)
+attributes = SubResource("CameraAttributesPhysical_drxnu")
+current = true
+
+[node name="LivingRoom" parent="." instance=ExtResource("1_oncn7")]
+
+[node name="Lightbulb1" type="OmniLight3D" parent="."]
+transform = Transform3D(0.707107, 0, 0.707107, 0, 1, 0, -0.707107, 0, 0.707107, 2, 3.19673, 0)
+light_intensity_lumens = 800.0
+light_temperature = 5000.0
+light_size = 0.1
+shadow_enabled = true
+
+[node name="Lightbulb2" type="OmniLight3D" parent="."]
+transform = Transform3D(0.707107, 0, 0.707107, 0, 1, 0, -0.707107, 0, 0.707107, -2, 3.197, 0)
+light_intensity_lumens = 800.0
+light_temperature = 5000.0
+light_size = 0.1
+shadow_enabled = true
+
+[node name="Options" type="Control" parent="." node_paths=PackedStringArray("sun", "lightbulb_1", "lightbulb_2", "world_environment")]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("2_hjhvo")
+sun = NodePath("../DirectionalLight3D")
+lightbulb_1 = NodePath("../Lightbulb1")
+lightbulb_2 = NodePath("../Lightbulb2")
+world_environment = NodePath("../WorldEnvironment")
+
+[node name="Light" type="VBoxContainer" parent="Options"]
+layout_mode = 0
+offset_left = 16.0
+offset_top = 16.0
+offset_right = 516.0
+offset_bottom = 69.0
+
+[node name="TimeOfDay" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/TimeOfDay"]
+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 = "Time of Day"
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/TimeOfDay"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+max_value = 1410.0
+step = 30.0
+value = 840.0
+
+[node name="Value" type="Label" parent="Options/Light/TimeOfDay"]
+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 = "14:00"
+vertical_alignment = 1
+
+[node name="SunIntensity" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/SunIntensity"]
+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 = "Sun Intensity"
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/SunIntensity"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+max_value = 200000.0
+step = 2000.0
+value = 100000.0
+
+[node name="Value" type="Label" parent="Options/Light/SunIntensity"]
+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 = "100000 lux"
+vertical_alignment = 1
+
+[node name="Lightbulb1Intensity" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/Lightbulb1Intensity"]
+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 = "Lightbulb 1 Intensity"
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/Lightbulb1Intensity"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+max_value = 3000.0
+step = 50.0
+value = 800.0
+
+[node name="Value" type="Label" parent="Options/Light/Lightbulb1Intensity"]
+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 = "800 lm"
+vertical_alignment = 1
+
+[node name="Lightbulb1Temperature" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/Lightbulb1Temperature"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+theme_override_font_sizes/font_size = 14
+text = "Lightbulb 1 Temperature"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/Lightbulb1Temperature"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+min_value = 1000.0
+max_value = 15000.0
+step = 100.0
+value = 5000.0
+
+[node name="Value" type="Label" parent="Options/Light/Lightbulb1Temperature"]
+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 = "5000 K"
+vertical_alignment = 1
+
+[node name="Lightbulb2Intensity" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/Lightbulb2Intensity"]
+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 = "Lightbulb 2 Intensity"
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/Lightbulb2Intensity"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+max_value = 3000.0
+step = 50.0
+value = 800.0
+
+[node name="Value" type="Label" parent="Options/Light/Lightbulb2Intensity"]
+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 = "800 lm"
+vertical_alignment = 1
+
+[node name="Lightbulb2Temperature" type="HBoxContainer" parent="Options/Light"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Light/Lightbulb2Temperature"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+theme_override_font_sizes/font_size = 14
+text = "Lightbulb 2 Temperature"
+vertical_alignment = 1
+
+[node name="HSlider" type="HSlider" parent="Options/Light/Lightbulb2Temperature"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+min_value = 1000.0
+max_value = 15000.0
+step = 100.0
+value = 5000.0
+
+[node name="Value" type="Label" parent="Options/Light/Lightbulb2Temperature"]
+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 = "5000 K"
+vertical_alignment = 1
+
+[node name="SDFGI" type="CheckButton" parent="Options/Light"]
+layout_mode = 2
+size_flags_horizontal = 0
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 4
+text = "SDF Global Illumination"
+
+[node name="Camera" type="VBoxContainer" parent="Options"]
+layout_mode = 1
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_left = 16.0
+offset_top = -42.0
+offset_right = 516.0
+offset_bottom = -16.0
+grow_vertical = 0
+
+[node name="AutoexposureSpeed" type="HBoxContainer" parent="Options/Camera"]
+layout_mode = 2
+theme_override_constants/separation = 15
+
+[node name="Label" type="Label" parent="Options/Camera/AutoexposureSpeed"]
+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 = "Auto Exposure Speed"
+
+[node name="HSlider" type="HSlider" parent="Options/Camera/AutoexposureSpeed"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+min_value = 0.1
+max_value = 10.0
+step = 0.1
+value = 1.0
+
+[node name="Value" type="Label" parent="Options/Camera/AutoexposureSpeed"]
+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 = "1.0"
+
+[connection signal="value_changed" from="Options/Light/TimeOfDay/HSlider" to="Options" method="_on_time_of_day_value_changed"]
+[connection signal="value_changed" from="Options/Light/SunIntensity/HSlider" to="Options" method="_on_sun_intensity_value_changed"]
+[connection signal="value_changed" from="Options/Light/Lightbulb1Intensity/HSlider" to="Options" method="_on_lightbulb1_intensity_value_changed"]
+[connection signal="value_changed" from="Options/Light/Lightbulb1Temperature/HSlider" to="Options" method="_on_lightbulb1_temperature_value_changed"]
+[connection signal="value_changed" from="Options/Light/Lightbulb2Intensity/HSlider" to="Options" method="_on_lightbulb2_intensity_value_changed"]
+[connection signal="value_changed" from="Options/Light/Lightbulb2Temperature/HSlider" to="Options" method="_on_lightbulb2_temperature_value_changed"]
+[connection signal="toggled" from="Options/Light/SDFGI" to="Options" method="_on_sdfgi_button_toggled"]
+[connection signal="value_changed" from="Options/Camera/AutoexposureSpeed/HSlider" to="Options" method="_on_autoexposure_speed_value_changed"]