Files
godot-demo-projects/3d/global_illumination/test.gd
2025-10-11 05:03:59 -07:00

265 lines
9.4 KiB
GDScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node3D
enum GIMode {
NONE,
LIGHTMAP_GI_ALL,
LIGHTMAP_GI_INDIRECT,
VOXEL_GI,
SDFGI,
MAX, # Maximum value of the enum, used internally.
}
enum ReflectionProbeMode {
NONE,
ONCE,
ALWAYS,
MAX,
}
enum SSILMode {
NONE,
SSAO,
SSIL,
SSAO_AND_SSIL,
MAX, # Maximum value of the enum, used internally.
}
# Keep this in sync with the SSILMode enum (except for MAX).
const SSIL_MODE_TEXTS = [
"Disabled (Fastest)",
"Screen-space ambient occlusion (Fast)",
"Screen-space indirect lighting (Average)",
"SSAO + SSIL (Slow)",
]
# Keep this in sync with the ReflectionProbeMode enum (except for MAX).
var reflection_probe_mode_texts: Array[String] = [
"Disabled - Using environment, VoxelGI or SDFGI reflections (Fast)",
"Enabled - \"Once\" Update Mode (Average)",
"Enabled - \"Always\" Update Mode (Slow)",
]
# Keep this in sync with the GIMode enum (except for MAX).
var gi_mode_texts: Array[String] = [
"Environment Lighting (Fastest)",
"Baked Lightmap All (Fast)",
"Baked Lightmap Indirect (Average)",
"VoxelGI (Slow)",
"SDFGI (Slow)",
]
var gi_mode := GIMode.NONE
var reflection_probe_mode := ReflectionProbeMode.NONE
var ssil_mode := SSILMode.NONE
var is_compatibility: bool = false
# This is replaced further below if using Compatibility to point to a newly created DirectionalLight3D
# (which does not affect sky rendering).
@onready var sun: DirectionalLight3D = $Sun
@onready var lightmap_gi_all_data: LightmapGIData = $LightmapGIAll.light_data
@onready var environment: Environment = $WorldEnvironment.environment
@onready var gi_mode_label: Label = $GIMode
@onready var reflection_probe_mode_label: Label = $ReflectionProbeMode
@onready var reflection_probe: ReflectionProbe = $Camera/ReflectiveSphere/ReflectionProbe
@onready var ssil_mode_label: Label = $SSILMode
# Several copies of the level mesh are required to cycle between different GI modes.
@onready var zdm2_lightmap_all: Node3D = $Zdm2LightmapAll
@onready var zdm2_lightmap_indirect: Node3D = $Zdm2LightmapIndirect
func _ready() -> void:
if RenderingServer.get_current_rendering_method() == "gl_compatibility":
is_compatibility = true
# Remove unsupported VoxelGI/SDFGI references from the label.
reflection_probe_mode_texts[0] = "Disabled - Using environment reflections (Fast)"
set_gi_mode(GIMode.NONE)
# Darken lights' energy to compensate for sRGB blending (without affecting sky rendering).
# This only applies to lights with shadows enabled.
$GrateOmniLight.light_energy = 0.25
$GarageOmniLight.light_energy = 0.5
sun.sky_mode = DirectionalLight3D.SKY_MODE_SKY_ONLY
sun = sun.duplicate()
sun.light_energy = 0.15
sun.sky_mode = DirectionalLight3D.SKY_MODE_LIGHT_ONLY
add_child(sun)
$Help.text = """Space: Cycle between GI modes
R: Cycle between reflection probe modes
Escape or F10: Toggle mouse capture"""
else:
set_gi_mode(gi_mode)
set_reflection_probe_mode(reflection_probe_mode)
set_ssil_mode(ssil_mode)
func _input(input_event: InputEvent) -> void:
if input_event.is_action_pressed(&"cycle_gi_mode"):
if is_compatibility:
# Only LightmapGI is supported in Compatibility.
# Note that the actual GI mode is the opposite of what's being set here, due to a bug
# in the Compatibility rendering method.
set_gi_mode(wrapi(gi_mode + 1, 0, GIMode.VOXEL_GI))
else:
set_gi_mode(wrapi(gi_mode + 1, 0, GIMode.MAX))
if input_event.is_action_pressed(&"cycle_reflection_probe_mode"):
set_reflection_probe_mode(wrapi(reflection_probe_mode + 1, 0, ReflectionProbeMode.MAX))
if input_event.is_action_pressed(&"cycle_ssil_mode"):
set_ssil_mode(wrapi(ssil_mode + 1, 0, SSILMode.MAX))
func set_gi_mode(p_gi_mode: GIMode) -> void:
gi_mode = p_gi_mode
gi_mode_label.text = "Global illumination: %s " % gi_mode_texts[gi_mode]
match p_gi_mode:
GIMode.NONE:
if is_compatibility:
# Work around Compatibility bug where lightmaps are still visible if the LightmapGI node is hidden.
$LightmapGIAll.light_data = null
$Zdm2LightmapAll.visible = true
$Zdm2LightmapIndirect.visible = false
# Halve sky contribution to prevent shaded areas from looking too bright and blue.
environment.ambient_light_sky_contribution = 0.5
$LightmapGIIndirect.visible = false
$LightmapGIAll.visible = false
$VoxelGI.visible = false
environment.sdfgi_enabled = false
# There is no difference between Indirect and Disabled when no GI is used.
# Pick the default value (which is Indirect).
sun.light_bake_mode = Light3D.BAKE_DYNAMIC
$GrateOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$GarageOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$CornerSpotLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$Camera/Box.gi_mode = GeometryInstance3D.GI_MODE_DISABLED
GIMode.LIGHTMAP_GI_ALL:
$Zdm2LightmapAll.visible = true
$Zdm2LightmapIndirect.visible = false
$LightmapGIAll.light_data = lightmap_gi_all_data
# Halve sky contribution to prevent dynamic objects from looking too bright and blue.
# (When using lightmaps, this property doesn't affect lightmapped surfaces.)
environment.ambient_light_sky_contribution = 0.5
$LightmapGIIndirect.visible = false
$LightmapGIAll.visible = true
$VoxelGI.visible = false
environment.sdfgi_enabled = false
# Make lights not affect baked surfaces by setting their bake mode to All.
sun.light_bake_mode = Light3D.BAKE_STATIC
$GrateOmniLight.light_bake_mode = Light3D.BAKE_STATIC
$GarageOmniLight.light_bake_mode = Light3D.BAKE_STATIC
$CornerSpotLight.light_bake_mode = Light3D.BAKE_STATIC
$Camera/Box.gi_mode = GeometryInstance3D.GI_MODE_DYNAMIC
GIMode.LIGHTMAP_GI_INDIRECT:
$LightmapGIAll.light_data = lightmap_gi_all_data
$Zdm2LightmapAll.visible = false
$Zdm2LightmapIndirect.visible = true
# Halve sky contribution to prevent dynamic objects from looking too bright and blue.
# (When using lightmaps, this property doesn't affect lightmapped surfaces.)
environment.ambient_light_sky_contribution = 0.5
$LightmapGIIndirect.visible = true
$LightmapGIAll.visible = false
$VoxelGI.visible = false
environment.sdfgi_enabled = false
sun.light_bake_mode = Light3D.BAKE_DYNAMIC
$GrateOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$GarageOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$CornerSpotLight.light_bake_mode = Light3D.BAKE_DYNAMIC
# Mark box as dynamic so it benefits from lightmap probes.
# Don't do this in other GI modes to avoid the heavy performance impact that
# happens with VoxelGI for dynamic objects.
$Camera/Box.gi_mode = GeometryInstance3D.GI_MODE_DYNAMIC
GIMode.VOXEL_GI:
# Work around bug where VoxelGI is not visible if the LightmapGI node is hidden (with LightmapGIData still present).
$LightmapGIAll.light_data = null
$Zdm2LightmapAll.visible = true
$Zdm2LightmapIndirect.visible = false
environment.ambient_light_sky_contribution = 1.0
$LightmapGIIndirect.visible = false
$LightmapGIAll.visible = false
$VoxelGI.visible = true
environment.sdfgi_enabled = false
# Bake mode must be Indirect, not Disabled. Otherwise, GI will
# not be visible for those lights.
sun.light_bake_mode = Light3D.BAKE_DYNAMIC
$GrateOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$GarageOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$CornerSpotLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$Camera/Box.gi_mode = GeometryInstance3D.GI_MODE_DISABLED
GIMode.SDFGI:
# Work around bug where SDFGI is not visible if the LightmapGI node is hidden (with LightmapGIData still present).
$LightmapGIAll.light_data = null
$Zdm2LightmapAll.visible = true
$Zdm2LightmapIndirect.visible = false
environment.ambient_light_sky_contribution = 1.0
$LightmapGIIndirect.visible = false
$LightmapGIAll.visible = false
$VoxelGI.visible = false
environment.sdfgi_enabled = true
# Bake mode must be Indirect, not Disabled. Otherwise, GI will
# not be visible for those lights.
sun.light_bake_mode = Light3D.BAKE_DYNAMIC
$GrateOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$GarageOmniLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$CornerSpotLight.light_bake_mode = Light3D.BAKE_DYNAMIC
$Camera/Box.gi_mode = GeometryInstance3D.GI_MODE_DISABLED
func set_reflection_probe_mode(p_reflection_probe_mode: ReflectionProbeMode) -> void:
reflection_probe_mode = p_reflection_probe_mode
reflection_probe_mode_label.text = "Reflection probe: %s " % reflection_probe_mode_texts[reflection_probe_mode]
match p_reflection_probe_mode:
ReflectionProbeMode.NONE:
reflection_probe.visible = false
reflection_probe.update_mode = ReflectionProbe.UPDATE_ONCE
ReflectionProbeMode.ONCE:
reflection_probe.visible = true
reflection_probe.update_mode = ReflectionProbe.UPDATE_ONCE
ReflectionProbeMode.ALWAYS:
reflection_probe.visible = true
reflection_probe.update_mode = ReflectionProbe.UPDATE_ALWAYS
func set_ssil_mode(p_ssil_mode: SSILMode) -> void:
ssil_mode = p_ssil_mode
if is_compatibility:
ssil_mode_label.text = "Screen-space lighting effects: Not supported on Compatibility"
ssil_mode_label.self_modulate.a = 0.6
return
else:
ssil_mode_label.text = "Screen-space lighting effects: %s " % SSIL_MODE_TEXTS[ssil_mode]
match p_ssil_mode:
SSILMode.NONE:
environment.ssao_enabled = false
environment.ssil_enabled = false
SSILMode.SSAO:
environment.ssao_enabled = true
environment.ssil_enabled = false
SSILMode.SSIL:
environment.ssao_enabled = false
environment.ssil_enabled = true
SSILMode.SSAO_AND_SSIL:
environment.ssao_enabled = true
environment.ssil_enabled = true