Merge pull request #888 from Calinou/add-physical-light-camera-units-demo

Add a 3D physical light and camera units demo
This commit is contained in:
Aaron Franke
2023-06-27 22:14:16 -05:00
committed by GitHub
12 changed files with 539 additions and 0 deletions

1
.gitignore vendored
View File

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

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -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

Binary file not shown.

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

View File

@@ -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"]