first commit

This commit is contained in:
sphynx-owner 2024-07-06 21:22:05 +03:00
commit 21b4e73ed7
906 changed files with 65701 additions and 0 deletions

101
Scripts/FoliageArea.gd Normal file
View file

@ -0,0 +1,101 @@
extends Area3D
var collider_audio_pair = []
@export var rustle_sounds: PackedScene
@export var placeholder: CollisionShape3D
const VELOCITY_ATTENUATION_THRESHOLD = 3.0
const ATTENUATION_ADJUST_SPEED = 200.0
const FADE_IN_OUT = 0.15
@onready var rustle_sounds_loaded = load(rustle_sounds.resource_path)
func _ready():
placeholder.queue_free()
var colliders = find_children("*", "CollisionShape3D", true)
for collider in colliders:
collider.reparent(self, true)
body_entered.connect(_on_body_entered)
body_exited.connect(_on_body_exited)
func _physics_process(delta):
for pair in collider_audio_pair:
pair["audio"].global_position = pair["collider"].global_position
var atten_speed = ATTENUATION_ADJUST_SPEED * delta
var atten_target = set_atten(pair["collider"], pair["audio"], true)
if pair["audio"].volume_db > atten_target:
atten_speed = atten_speed / 3.0
pair["audio"].volume_db = move_toward(pair["audio"].volume_db, atten_target, atten_speed)
# should change to get_atten sometime
func set_atten(phys_obj, audio, get_vol := false):
var collider_velocity
if phys_obj is CharacterBody3D:
collider_velocity = phys_obj.get_real_velocity().length()
else:
if phys_obj.linear_velocity.length() > phys_obj.angular_velocity.length():
collider_velocity = phys_obj.linear_velocity.length()
else:
collider_velocity = phys_obj.angular_velocity.length()
var rustle_atten = collider_velocity/VELOCITY_ATTENUATION_THRESHOLD
rustle_atten = clamp(rustle_atten, 0.0, 1.0)
var vol = lerp(-80.0, 0.0, ease_out_circ(rustle_atten))
if get_vol:
return vol
else:
audio.volume_db = vol
func _on_body_entered(body):
if body is RigidBody3D or CharacterBody3D:
var rustle_sounds = rustle_sounds_loaded.instantiate()
get_tree().root.get_child(0).add_child(rustle_sounds)
# is this fade in necessary? the move_towards behavior should already act as its own fade in right? only fade out is necessary due to abrupt deletion without it?
var target_vol = set_atten(body, rustle_sounds, true)
var fade_time = FADE_IN_OUT
while fade_time > 0.0:
rustle_sounds.global_position = body.global_position
rustle_sounds.volume_db = lerp(-80.0, target_vol, (FADE_IN_OUT-fade_time)/FADE_IN_OUT)
await get_tree().process_frame
fade_time -= get_process_delta_time()
if overlaps_body(body):
# this check sometimes fails because godot doesn't guarantee up to date results
# so sometimes you'll get the bug where the foliage noise keeps on playing after you get out of foliage
# i'm too tired to fix this, this script is bloated enough as it is
# interestingly enough i've run into this bug in other AAA games as well
collider_audio_pair.append({"collider": body, "audio": rustle_sounds})
else:
var from_vol = set_atten(body, rustle_sounds, true)
var fade_time2 = FADE_IN_OUT
while fade_time2 > 0.0:
rustle_sounds.global_position = body.global_position
rustle_sounds.volume_db = lerp(from_vol, -80.0, (FADE_IN_OUT-fade_time2)/FADE_IN_OUT)
await get_tree().process_frame
fade_time2 -= get_process_delta_time()
rustle_sounds.queue_free()
func _on_body_exited(body):
for pair in collider_audio_pair:
if pair["collider"] == body:
var temp_audio = pair["audio"]
var temp_obj = pair["collider"]
collider_audio_pair.erase(pair)
var from_vol = set_atten(body, rustle_sounds, true)
var fade_time = FADE_IN_OUT
while fade_time > 0.0:
temp_audio.global_position = temp_obj.global_position
temp_audio.volume_db = lerp(from_vol, -80.0, (FADE_IN_OUT-fade_time)/FADE_IN_OUT)
await get_tree().process_frame
fade_time -= get_process_delta_time()
temp_audio.queue_free()
break
func ease_out_circ(lerp: float) -> float:
return sqrt(1.0 - pow(lerp - 1.0, 2.0))

View file

@ -0,0 +1,68 @@
@tool
extends Node
@export_category("Set Lighting Scenario")
@export var set_dusk: bool = false : set = apply_dusk
@export var set_noon: bool = false : set = apply_noon
@export var set_afternoon: bool = false : set = apply_afternoon
@export var set_night: bool = false : set = apply_night
@export_category("")
@export var UI: UIController
@onready var sun_orig_res = ProjectSettings.get_setting("rendering/lights_and_shadows/directional_shadow/size")
@onready var sun_shadow_bits = ProjectSettings.get_setting("rendering/lights_and_shadows/directional_shadow/16_bits")
func apply_dusk(dummy: bool) -> void:
apply_lighting(UI.lighting_scenarios.dusk)
func apply_noon(dummy: bool) -> void:
apply_lighting(UI.lighting_scenarios.noon)
func apply_afternoon(dummy: bool) -> void:
apply_lighting(UI.lighting_scenarios.afternoon)
func apply_night(dummy: bool) -> void:
apply_lighting(UI.lighting_scenarios.night)
func apply_lighting(lighting):
UI.sun_light.light_intensity_lux = lighting.lux
UI.sun_light.light_temperature = lighting.temp
UI.sun_light.quaternion = lighting.rotation
UI.environment.environment.background_intensity = lighting.sky_nits
UI.environment.camera_attributes.exposure_sensitivity = lighting.exposure_mult
UI.environment.camera_attributes.auto_exposure_min_sensitivity = lighting.exposure_min_sens
if lighting.night_lights:
for node in UI.night_lights:
node.visible = true
change_shadow_casters(false)
RenderingServer.directional_shadow_atlas_set_size(UI.NIGHT_SHADOW_RES, sun_shadow_bits)
for mat in UI.emissives:
mat.emission_enabled = true
else:
for node in UI.night_lights:
node.visible = false
change_shadow_casters(true)
RenderingServer.directional_shadow_atlas_set_size(sun_orig_res, sun_shadow_bits)
for mat in UI.emissives:
mat.emission_enabled = false
UI.environment.environment.sdfgi_enabled = false
await get_tree().create_timer(0.1).timeout
UI.environment.environment.sdfgi_enabled = true
func change_shadow_casters(is_cast_on):
var shadow_mode
if is_cast_on:
shadow_mode = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
else:
shadow_mode = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
for node in UI.lamp_mesh_containers:
for mesh in node.get_children():
if mesh is MeshInstance3D:
mesh.cast_shadow = shadow_mode
for mesh in UI.lamp_meshes:
mesh.cast_shadow = shadow_mode

11
Scripts/Lighting.gd Normal file
View file

@ -0,0 +1,11 @@
extends Resource
class_name Lighting
@export var rotation: Quaternion = Quaternion.IDENTITY
@export var temp: float = 0.0
@export var lux: float = 0.0
@export var sky_nits: float = 0.0
@export var night_lights: bool = false
@export var exposure_mult: float = 0.0
@export var exposure_min_sens: float = 0.0

View file

@ -0,0 +1,8 @@
extends Resource
class_name LightingScenarios
@export var dusk: Lighting = null
@export var noon: Lighting = null
@export var afternoon: Lighting = null
@export var night: Lighting = null

View file

@ -0,0 +1,89 @@
extends Node3D
@export_category("ceiling/floor to play audio")
@export var impulse_force_ceiling_for_prop_impact_play: float = 1200.0
@export_range (0.0, 1.0) var attenuation_percent_threshold_to_play: float = 0.2
@export_category("sounds to use")
@export var prop_sounds: Array[AudioStreamWAV]
@export var scrape_sound: AudioStreamWAV
@export_category("system")
@export var helper_script: GDScript
#set to 99999 to mute prop audio
const AUDIO_START_TIMEOUT = 0.75
const PROP_PLAY_TIMEOUT = 0.15
const VELOCITY_CEILING_FOR_SCRAPE_PLAY = 10.0
const SCRAPE_PLAY_TIMEOUT = 0.15
var prop_sounds_loaded = []
var on_cooldown = false
var scraping_on_cooldown = false
var audio_lock = true
@onready var parent_with_helper = $"../"
@onready var phys_sound_player = $"Prop"
@onready var scrape_sound_player = $"Scrape"
func _ready():
parent_with_helper.set_script(load(helper_script.resource_path))
for resource in prop_sounds:
prop_sounds_loaded.append(load(resource.resource_path))
scrape_sound_player.stream = load(scrape_sound.resource_path)
scrape_sound_player.play()
await get_tree().create_timer(AUDIO_START_TIMEOUT).timeout
audio_lock = false
func _process(delta):
pass
func recieve_physics_process(delta):
if audio_lock:
return
var scrape_attenuation
if parent_with_helper.get_contact_count() > 0:
scrape_attenuation = parent_with_helper.linear_velocity.length()/VELOCITY_CEILING_FOR_SCRAPE_PLAY
scrape_attenuation = clamp(scrape_attenuation, 0.0, 1.0)
else:
scrape_attenuation = 0.0
set_scraping_pause(scrape_attenuation)
func set_scraping_pause(attenuation):
if scraping_on_cooldown:
return
#the scraping sound needs to fade in and out?
scraping_on_cooldown = true
scrape_sound_player.volume_db = lerp(-80.0, 0.0, ease_out_circ(attenuation))
await get_tree().create_timer(SCRAPE_PLAY_TIMEOUT).timeout
scraping_on_cooldown = false
func recieve_integrate_forces(state):
if audio_lock:
return
if on_cooldown:
return
var strongest_contact_impulse = 0.0
for index in state.get_contact_count():
if state.get_contact_impulse(index).length() > strongest_contact_impulse:
strongest_contact_impulse = state.get_contact_impulse(index).length()
var loud_scale = strongest_contact_impulse/(impulse_force_ceiling_for_prop_impact_play * state.step)
loud_scale = clamp(loud_scale, 0.0, 1.0)
if loud_scale > attenuation_percent_threshold_to_play:
on_cooldown = true
phys_sound_player.stream = prop_sounds_loaded.pick_random()
phys_sound_player.volume_db = lerp(-80.0, 0.0, ease_out_circ(loud_scale))
phys_sound_player.play()
await get_tree().create_timer(PROP_PLAY_TIMEOUT).timeout
on_cooldown = false
func ease_out_circ(lerp: float) -> float:
return sqrt(1.0 - pow(lerp - 1.0, 2.0))

View file

@ -0,0 +1,7 @@
extends RigidBody3D
func _physics_process(delta):
$"PropAudioPlayer".recieve_physics_process(delta)
func _integrate_forces(state):
$"PropAudioPlayer".recieve_integrate_forces(state)

View file

@ -0,0 +1,7 @@
extends Resource
class_name ScalabilitySettings
@export var low: Settings = null
@export var normal: Settings = null
@export var high: Settings = null

13
Scripts/Settings.gd Normal file
View file

@ -0,0 +1,13 @@
extends Resource
class_name Settings
@export var sun_angle: float = 0.0
@export var ssr: bool = false
@export var ssao: bool = false
@export var ssil: bool = false
@export var sdfgi: bool = false
@export var night_shadows: bool = false
@export var msaa: Viewport.MSAA = Viewport.MSAA_DISABLED
@export var fxaa: RenderingServer.ViewportScreenSpaceAA = RenderingServer.VIEWPORT_SCREEN_SPACE_AA_DISABLED
@export var scaling: RenderingServer.ViewportScaling3DMode = RenderingServer.VIEWPORT_SCALING_3D_MODE_BILINEAR

306
Scripts/UIController.gd Normal file
View file

@ -0,0 +1,306 @@
extends Control
class_name UIController
@export_category("Toggles")
@export var enable_profiler : bool
@export var enable_music : bool
@export_category("Resources")
@export var settings: ScalabilitySettings
@export var lighting_scenarios: LightingScenarios
@export_category("")
@export var custom_res_text_box : LineEdit
@export var fps_text : Label
@export var custom_res: Array[Control]
@export var profiler: Array[Control]
@export var sun_light: DirectionalLight3D
@export var environment: WorldEnvironment
@export var night_lights: Array[Node3D]
@export var day_lights: Node3D
@export var lamp_mesh_containers: Array[Node3D]
@export var lamp_meshes: Array[MeshInstance3D]
@export var emissives: Array[StandardMaterial3D]
@export var scalable_night_lights: Node3D
@export var day_ambient_audio: AudioStreamPlayer
@export var night_ambient_audio: AudioStreamPlayer
@export var day_music: AudioStreamPlayer
@export var night_music: AudioStreamPlayer
const UPPER_RES_LIMIT = 8640.0
const LOWER_RES_LIMIT = 96.0
const TIME_CHANGE_DURATION = 4.0
const NIGHT_SHADOW_RES = 512
var renderTargetVertical = 1080.0
var is_time_changing = false
var is_ui_hidden = false
var ui_cooldown = false
var fps
var frametime
var draw_calls
var memory
var vram
@onready var sun_orig_res = ProjectSettings.get_setting("rendering/lights_and_shadows/directional_shadow/size")
@onready var sun_shadow_bits = ProjectSettings.get_setting("rendering/lights_and_shadows/directional_shadow/16_bits")
func _ready():
refresh_performance()
_on_res_selected(2)
_on_quality_selected(1)
_on_time_selected(2)
get_viewport().connect("size_changed", _on_viewport_resize)
if !enable_profiler:
for control in profiler:
control.visible = false
func _process(delta):
pass
func _on_viewport_resize():
if renderTargetVertical == 0.0:
RenderingServer.viewport_set_scaling_3d_scale(get_viewport().get_viewport_rid(), 1)
return
RenderingServer.viewport_set_scaling_3d_scale(get_viewport().get_viewport_rid(), renderTargetVertical/float(get_resolution_actual()))
func get_resolution_actual():
var yToUse
var project_width = float(ProjectSettings.get_setting("display/window/size/viewport_width"))
var project_height = float(ProjectSettings.get_setting("display/window/size/viewport_height"))
var viewport_width = float(get_viewport().size.x)
var viewport_height = float(get_viewport().size.y)
if viewport_width/viewport_height < project_width/project_height:
yToUse = (viewport_width/project_width) * project_height
else:
yToUse = viewport_height
return int(yToUse)
func refresh_performance():
fps = "FPS: " + str(Performance.get_monitor(Performance.TIME_FPS))
frametime = "Frame time: " + str(snapped(Performance.get_monitor(Performance.TIME_PROCESS) * 1000.0, 0.01)) + " ms"
draw_calls = "Draw calls: " + str(Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME))
memory = "RAM: " + str(snapped(Performance.get_monitor(Performance.MEMORY_STATIC) * 0.000001, 0.01)) + " MB"
vram = "VRAM: " + str(snapped(Performance.get_monitor(Performance.RENDER_VIDEO_MEM_USED) * 0.000001, 0.01)) + " MB"
fps_text.text = fps + "\n" + frametime + "\n" + draw_calls + "\n" + memory + "\n" + vram
await get_tree().create_timer(0.75).timeout
refresh_performance()
func _on_res_selected(index):
if index == 6:
if renderTargetVertical == 0.0:
custom_res_text_box.text = str(get_resolution_actual())
else:
custom_res_text_box.text = str(int(renderTargetVertical))
for control in custom_res:
control.visible = true
else:
match index:
0:
renderTargetVertical = 0.0
1:
renderTargetVertical = 480.0
2:
renderTargetVertical = 720.0
3:
renderTargetVertical = 1080.0
4:
renderTargetVertical = 1440.0
5:
renderTargetVertical = 2160.0
_on_viewport_resize()
for control in custom_res:
control.visible = false
func _on_custom_res_input(input_string):
custom_res_text_box.release_focus()
renderTargetVertical = clamp(float(input_string), LOWER_RES_LIMIT, UPPER_RES_LIMIT)
custom_res_text_box.text = str(int(renderTargetVertical))
_on_viewport_resize()
func _on_quality_selected(index):
match index:
0:
apply_settings(settings.low)
1:
apply_settings(settings.normal)
2:
apply_settings(settings.high)
func _on_time_selected(index):
match index:
0:
apply_time(lighting_scenarios.dusk)
1:
apply_time(lighting_scenarios.noon)
2:
apply_time(lighting_scenarios.afternoon)
3:
apply_time(lighting_scenarios.night)
func _on_quit_selected():
get_tree().quit()
func apply_settings(settings):
sun_light.light_angular_distance = settings.sun_angle
environment.environment.ssr_enabled = settings.ssr
environment.environment.ssao_enabled = settings.ssao
environment.environment.ssil_enabled = settings.ssil
environment.environment.sdfgi_enabled = settings.sdfgi
RenderingServer.viewport_set_msaa_3d(get_viewport().get_viewport_rid(), settings.msaa)
RenderingServer.viewport_set_screen_space_aa(get_viewport().get_viewport_rid(), settings.fxaa)
RenderingServer.viewport_set_scaling_3d_mode(get_viewport().get_viewport_rid(), settings.scaling)
for light in scalable_night_lights.get_children():
if light is Light3D:
light.shadow_enabled = settings.night_shadows
func apply_time(lighting):
is_time_changing = false
await get_tree().process_frame
var time = Time.get_ticks_msec() / 1000.0
var orig_lux = sun_light.light_intensity_lux
var orig_light = sun_light.light_temperature
var orig_rot = sun_light.quaternion
var orig_sky = environment.environment.background_intensity
var orig_exp_mult = environment.camera_attributes.exposure_sensitivity
var orig_min_sens = environment.camera_attributes.auto_exposure_min_sensitivity
var orig_day_volume = day_ambient_audio.volume_db
var orig_night_volume = night_ambient_audio.volume_db
var orig_day_music_volume = day_music.volume_db
var orig_night_music_volume = night_music.volume_db
var target_music_audio
if enable_music:
target_music_audio = 0.0
else:
target_music_audio = -80.0
if lighting.night_lights:
if day_music.playing:
night_music.stop()
else:
for node in night_lights:
node.visible = false
change_shadow_casters(true)
RenderingServer.directional_shadow_atlas_set_size(sun_orig_res, sun_shadow_bits)
for mat in emissives:
mat.emission_enabled = false
if night_music.playing:
day_music.stop()
is_time_changing = true
while is_time_changing:
var current_time = Time.get_ticks_msec() / 1000.0
var lerp = (current_time - time)/TIME_CHANGE_DURATION
if lerp > 1:
sun_light.light_intensity_lux = lighting.lux
sun_light.light_temperature = lighting.temp
sun_light.quaternion = lighting.rotation
environment.environment.background_intensity = lighting.sky_nits
environment.camera_attributes.exposure_sensitivity = lighting.exposure_mult
environment.camera_attributes.auto_exposure_min_sensitivity = lighting.exposure_min_sens
if lighting.night_lights:
for node in night_lights:
node.visible = true
change_shadow_casters(false)
RenderingServer.directional_shadow_atlas_set_size(NIGHT_SHADOW_RES, sun_shadow_bits)
for mat in emissives:
mat.emission_enabled = true
day_ambient_audio.volume_db = -80.0
night_ambient_audio.volume_db = 0.0
day_music.volume_db = -80.0
night_music.volume_db = target_music_audio
if day_music.playing:
day_music.stop()
night_music.play()
else:
day_ambient_audio.volume_db = 0.0
night_ambient_audio.volume_db = -80.0
day_music.volume_db = target_music_audio
night_music.volume_db = -80.0
if night_music.playing:
night_music.stop()
day_music.play()
is_time_changing = false
break
sun_light.light_intensity_lux = lerp(orig_lux, lighting.lux, easeInOutSine(lerp))
sun_light.light_temperature = lerp(orig_light, lighting.temp, easeInOutSine(lerp))
sun_light.quaternion = orig_rot.slerp(lighting.rotation, easeInOutSine(lerp))
environment.environment.background_intensity = lerp(orig_sky, lighting.sky_nits, easeInOutSine(lerp))
if orig_exp_mult < lighting.exposure_mult:
environment.camera_attributes.exposure_sensitivity = lerp(orig_exp_mult, lighting.exposure_mult, easeInExp(lerp, 150))
environment.camera_attributes.auto_exposure_min_sensitivity = lerp(orig_min_sens, lighting.exposure_min_sens, easeInExp(lerp, 150))
else:
environment.camera_attributes.exposure_sensitivity = lerp(orig_exp_mult, lighting.exposure_mult, easeOutExp(lerp, 150))
environment.camera_attributes.auto_exposure_min_sensitivity = lerp(orig_min_sens, lighting.exposure_min_sens, easeOutExp(lerp, 150))
var music_lerp_exp = 5
if lighting.night_lights:
day_ambient_audio.volume_db = lerp(orig_day_volume, -80.0, easeInExp(lerp, 4))
night_ambient_audio.volume_db = lerp(orig_night_volume, 0.0, easeOutExp(lerp, 4))
day_music.volume_db = lerp(orig_day_music_volume, -80.0, easeInExp(lerp, music_lerp_exp))
night_music.volume_db = lerp(orig_night_music_volume, target_music_audio, easeOutExp(lerp, music_lerp_exp))
else:
day_ambient_audio.volume_db = lerp(orig_day_volume, 0.0, easeOutExp(lerp, 4))
night_ambient_audio.volume_db = lerp(orig_night_volume, -80.0, easeInExp(lerp, 4))
day_music.volume_db = lerp(orig_day_music_volume, target_music_audio, easeOutExp(lerp, music_lerp_exp))
night_music.volume_db = lerp(orig_night_music_volume, -80.0, easeInExp(lerp, music_lerp_exp))
await get_tree().process_frame
func change_shadow_casters(is_cast_on):
var shadow_mode
if is_cast_on:
shadow_mode = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
else:
shadow_mode = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
for node in lamp_mesh_containers:
for mesh in node.get_children():
if mesh is MeshInstance3D:
mesh.cast_shadow = shadow_mode
for mesh in lamp_meshes:
mesh.cast_shadow = shadow_mode
func switch_visibility():
ui_cooldown = true
visible = !is_ui_hidden
await get_tree().create_timer(0.5).timeout
ui_cooldown = false
func _unhandled_input(event):
if event is InputEventKey:
match event.keycode:
KEY_H:
if !ui_cooldown:
is_ui_hidden = !is_ui_hidden
switch_visibility()
func easeInOutSine(lerp: float) -> float:
return clamp(-(cos(PI * lerp) - 1.0) / 2.0, 0.0, 1.0)
func easeInExp(x: float, exp: int) -> float:
return clamp(pow(x, exp), 0.0, 1.0)
func easeOutExp(x: float, exp: int) -> float:
return clamp(1.0 - pow(1.0 - x, exp), 0.0, 1.0)