Initial commit

This commit is contained in:
2023-10-26 15:27:25 +02:00
commit 7ed5f3155e
25 changed files with 1565 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# Godot 4+ specific ignores
.godot/

View File

@@ -0,0 +1,21 @@
# MIT License
Copyright © 2023-present Hugo Locurcio and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,462 @@
extends Control
@export var fps: Label
@export var frame_time: Label
@export var frame_number: Label
@export var frame_history_total_avg: Label
@export var frame_history_total_min: Label
@export var frame_history_total_max: Label
@export var frame_history_total_last: Label
@export var frame_history_cpu_avg: Label
@export var frame_history_cpu_min: Label
@export var frame_history_cpu_max: Label
@export var frame_history_cpu_last: Label
@export var frame_history_gpu_avg: Label
@export var frame_history_gpu_min: Label
@export var frame_history_gpu_max: Label
@export var frame_history_gpu_last: Label
@export var fps_graph: Panel
@export var total_graph: Panel
@export var cpu_graph: Panel
@export var gpu_graph: Panel
@export var information: Label
@export var settings: Label
## The number of frames to keep in history for graph drawing and best/worst calculations.
## Currently, this also affects how FPS is measured.
const HISTORY_NUM_FRAMES = 150
const GRAPH_SIZE = Vector2(150, 25)
const GRAPH_MIN_FPS = 10
const GRAPH_MAX_FPS = 160
const GRAPH_MIN_FRAMETIME = 1.0 / GRAPH_MIN_FPS
const GRAPH_MAX_FRAMETIME = 1.0 / GRAPH_MAX_FPS
## Debug menu display style.
enum Style {
HIDDEN, ## Debug menu is hidden.
VISIBLE_COMPACT, ## Debug menu is visible, with only the FPS, FPS cap (if any) and time taken to render the last frame.
VISIBLE_DETAILED, ## Debug menu is visible with full information, including graphs.
MAX, ## Represents the size of the Style enum.
}
## The style to use when drawing the debug menu.
var style := Style.HIDDEN:
set(value):
style = value
match style:
Style.HIDDEN:
visible = false
Style.VISIBLE_COMPACT, Style.VISIBLE_DETAILED:
visible = true
frame_number.visible = style == Style.VISIBLE_DETAILED
$VBoxContainer/FrameTimeHistory.visible = style == Style.VISIBLE_DETAILED
$VBoxContainer/FPSGraph.visible = style == Style.VISIBLE_DETAILED
$VBoxContainer/TotalGraph.visible = style == Style.VISIBLE_DETAILED
$VBoxContainer/CPUGraph.visible = style == Style.VISIBLE_DETAILED
$VBoxContainer/GPUGraph.visible = style == Style.VISIBLE_DETAILED
information.visible = style == Style.VISIBLE_DETAILED
settings.visible = style == Style.VISIBLE_DETAILED
# Value of `Time.get_ticks_usec()` on the previous frame.
var last_tick := 0
var thread := Thread.new()
## Returns the sum of all values of an array (use as a parameter to `Array.reduce()`).
var sum_func := func avg(accum: float, number: float) -> float: return accum + number
# History of the last `HISTORY_NUM_FRAMES` rendered frames.
var frame_history_total: Array[float] = []
var frame_history_cpu: Array[float] = []
var frame_history_gpu: Array[float] = []
var fps_history: Array[float] = [] # Only used for graphs.
var frametime_avg := GRAPH_MIN_FRAMETIME
var frametime_cpu_avg := GRAPH_MAX_FRAMETIME
var frametime_gpu_avg := GRAPH_MIN_FRAMETIME
var frames_per_second := float(GRAPH_MIN_FPS)
var frame_time_gradient := Gradient.new()
func _init() -> void:
# This must be done here instead of `_ready()` to avoid having `visibility_changed` be emitted immediately.
visible = false
if not InputMap.has_action("cycle_debug_menu"):
# Create default input action if no user-defined override exists.
# We can't do it in the editor plugin's activation code as it doesn't seem to work there.
InputMap.add_action("cycle_debug_menu")
var event := InputEventKey.new()
event.keycode = KEY_F3
InputMap.action_add_event("cycle_debug_menu", event)
func _ready() -> void:
fps_graph.draw.connect(_fps_graph_draw)
total_graph.draw.connect(_total_graph_draw)
cpu_graph.draw.connect(_cpu_graph_draw)
gpu_graph.draw.connect(_gpu_graph_draw)
fps_history.resize(HISTORY_NUM_FRAMES)
frame_history_total.resize(HISTORY_NUM_FRAMES)
frame_history_cpu.resize(HISTORY_NUM_FRAMES)
frame_history_gpu.resize(HISTORY_NUM_FRAMES)
# NOTE: Both FPS and frametimes are colored following FPS logic
# (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
# This makes the color gradient non-linear.
# Colors are taken from <https://tailwindcolor.com/>.
frame_time_gradient.set_color(0, Color8(239, 68, 68)) # red-500
frame_time_gradient.set_color(1, Color8(56, 189, 248)) # light-blue-400
frame_time_gradient.add_point(0.3333, Color8(250, 204, 21)) # yellow-400
frame_time_gradient.add_point(0.6667, Color8(128, 226, 95)) # 50-50 mix of lime-400 and green-400
get_viewport().size_changed.connect(update_settings_label)
# Display loading text while information is being queried,
# in case the user toggles the full debug menu just after starting the project.
information.text = "Loading hardware information...\n\n "
settings.text = "Loading project information..."
thread.start(
func():
# Disable thread safety checks as they interfere with this add-on.
# This only affects this particular thread, not other thread instances in the project.
# See <https://github.com/godotengine/godot/pull/78000> for details.
# Use a Callable so that this can be ignored on Godot 4.0 without causing a script error
# (thread safety checks were added in Godot 4.1).
if Engine.get_version_info()["hex"] >= 0x040100:
Callable(Thread, "set_thread_safety_checks_enabled").call(false)
# Enable required time measurements to display CPU/GPU frame time information.
# These lines are time-consuming operations, so run them in a separate thread.
RenderingServer.viewport_set_measure_render_time(get_viewport().get_viewport_rid(), true)
update_information_label()
update_settings_label()
)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("cycle_debug_menu"):
style = wrapi(style + 1, 0, Style.MAX) as Style
func _exit_tree() -> void:
thread.wait_to_finish()
## Update hardware information label (this can change at runtime based on window
## size and graphics settings). This is only called when the window is resized.
## To update when graphics settings are changed, the function must be called manually
## using `DebugMenu.update_settings_label()`.
func update_settings_label() -> void:
settings.text = ""
if ProjectSettings.has_setting("application/config/version"):
settings.text += "Project Version: %s\n" % ProjectSettings.get_setting("application/config/version")
var rendering_method_string := ""
match str(ProjectSettings.get_setting("rendering/renderer/rendering_method")):
"forward_plus":
rendering_method_string = "Forward+"
"mobile":
rendering_method_string = "Forward Mobile"
"gl_compatibility":
rendering_method_string = "Compatibility"
settings.text += "Rendering Method: %s\n" % rendering_method_string
var viewport := get_viewport()
# The size of the viewport rendering, which determines which resolution 3D is rendered at.
var viewport_render_size := Vector2i()
if viewport.content_scale_mode == Window.CONTENT_SCALE_MODE_VIEWPORT:
viewport_render_size = viewport.get_visible_rect().size
settings.text += "Viewport: %d×%d, Window: %d×%d\n" % [viewport.get_visible_rect().size.x, viewport.get_visible_rect().size.y, viewport.size.x, viewport.size.y]
else:
# Window size matches viewport size.
viewport_render_size = viewport.size
settings.text += "Viewport: %d×%d\n" % [viewport.size.x, viewport.size.y]
# Display 3D settings only if relevant.
if viewport.get_camera_3d():
var antialiasing_3d_string := ""
if viewport.use_taa:
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "TAA"
if viewport.msaa_3d >= Viewport.MSAA_2X:
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "%d× MSAA" % pow(2, viewport.msaa_3d)
if viewport.screen_space_aa == Viewport.SCREEN_SPACE_AA_FXAA:
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "FXAA"
var scaling_mode = "Unknown"
match viewport.scaling_3d_mode:
Viewport.SCALING_3D_MODE_BILINEAR:
scaling_mode = "Bilinear"
Viewport.SCALING_3D_MODE_FSR:
scaling_mode = "FSR 1.0"
Viewport.SCALING_3D_MODE_FSR2:
scaling_mode = "FSR 2.2"
settings.text += "3D scale (%s): %d%% = %d×%d" % [
scaling_mode,
viewport.scaling_3d_scale * 100,
viewport_render_size.x * viewport.scaling_3d_scale,
viewport_render_size.y * viewport.scaling_3d_scale,
]
if not antialiasing_3d_string.is_empty():
settings.text += "\n3D Antialiasing: %s" % antialiasing_3d_string
var environment := viewport.get_camera_3d().get_world_3d().environment
if environment:
if environment.ssr_enabled:
settings.text += "\nSSR: %d Steps" % environment.ssr_max_steps
if environment.ssao_enabled:
settings.text += "\nSSAO: On"
if environment.ssil_enabled:
settings.text += "\nSSIL: On"
if environment.sdfgi_enabled:
settings.text += "\nSDFGI: %d Cascades" % environment.sdfgi_cascades
if environment.glow_enabled:
settings.text += "\nGlow: On"
if environment.volumetric_fog_enabled:
settings.text += "\nVolumetric Fog: On"
var antialiasing_2d_string := ""
if viewport.msaa_2d >= Viewport.MSAA_2X:
antialiasing_2d_string = "%d× MSAA" % pow(2, viewport.msaa_2d)
if not antialiasing_2d_string.is_empty():
settings.text += "\n2D Antialiasing: %s" % antialiasing_2d_string
## Update hardware/software information label (this never changes at runtime).
func update_information_label() -> void:
var adapter_string := ""
# Make "NVIDIA Corporation" and "NVIDIA" be considered identical (required when using OpenGL to avoid redundancy).
if RenderingServer.get_video_adapter_vendor().trim_suffix(" Corporation") in RenderingServer.get_video_adapter_name():
# Avoid repeating vendor name before adapter name.
# Trim redundant suffix sometimes reported by NVIDIA graphics cards when using OpenGL.
adapter_string = RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
else:
adapter_string = RenderingServer.get_video_adapter_vendor() + " - " + RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
# Graphics driver version information isn't always availble.
var driver_info := OS.get_video_adapter_driver_info()
var driver_info_string := ""
if driver_info.size() >= 2:
driver_info_string = driver_info[1]
else:
driver_info_string = "(unknown)"
var release_string := ""
if OS.has_feature("editor"):
# Editor build (implies `debug`).
release_string = "editor"
elif OS.has_feature("debug"):
# Debug export template build.
release_string = "debug"
else:
# Release export template build.
release_string = "release"
var graphics_api_string := ""
if str(ProjectSettings.get_setting("rendering/renderer/rendering_method")) != "gl_compatibility":
graphics_api_string = "Vulkan"
else:
if OS.has_feature("web"):
graphics_api_string = "WebGL"
elif OS.has_feature("mobile"):
graphics_api_string = "OpenGL ES"
else:
graphics_api_string = "OpenGL"
information.text = (
"%s, %d threads\n" % [OS.get_processor_name().replace("(R)", "").replace("(TM)", ""), OS.get_processor_count()]
+ "%s %s (%s %s), %s %s\n" % [OS.get_name(), "64-bit" if OS.has_feature("64") else "32-bit", release_string, "double" if OS.has_feature("double") else "single", graphics_api_string, RenderingServer.get_video_adapter_api_version()]
+ "%s, %s" % [adapter_string, driver_info_string]
)
func _fps_graph_draw() -> void:
var fps_polyline := PackedVector2Array()
fps_polyline.resize(HISTORY_NUM_FRAMES)
for fps_index in fps_history.size():
fps_polyline[fps_index] = Vector2(
remap(fps_index, 0, fps_history.size(), 0, GRAPH_SIZE.x),
remap(clampf(fps_history[fps_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
)
# Don't use antialiasing to speed up line drawing, but use a width that scales with
# viewport scale to keep the line easily readable on hiDPI displays.
fps_graph.draw_polyline(fps_polyline, frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
func _total_graph_draw() -> void:
var total_polyline := PackedVector2Array()
total_polyline.resize(HISTORY_NUM_FRAMES)
for total_index in frame_history_total.size():
total_polyline[total_index] = Vector2(
remap(total_index, 0, frame_history_total.size(), 0, GRAPH_SIZE.x),
remap(clampf(frame_history_total[total_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
)
# Don't use antialiasing to speed up line drawing, but use a width that scales with
# viewport scale to keep the line easily readable on hiDPI displays.
total_graph.draw_polyline(total_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
func _cpu_graph_draw() -> void:
var cpu_polyline := PackedVector2Array()
cpu_polyline.resize(HISTORY_NUM_FRAMES)
for cpu_index in frame_history_cpu.size():
cpu_polyline[cpu_index] = Vector2(
remap(cpu_index, 0, frame_history_cpu.size(), 0, GRAPH_SIZE.x),
remap(clampf(frame_history_cpu[cpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
)
# Don't use antialiasing to speed up line drawing, but use a width that scales with
# viewport scale to keep the line easily readable on hiDPI displays.
cpu_graph.draw_polyline(cpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
func _gpu_graph_draw() -> void:
var gpu_polyline := PackedVector2Array()
gpu_polyline.resize(HISTORY_NUM_FRAMES)
for gpu_index in frame_history_gpu.size():
gpu_polyline[gpu_index] = Vector2(
remap(gpu_index, 0, frame_history_gpu.size(), 0, GRAPH_SIZE.x),
remap(clampf(frame_history_gpu[gpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
)
# Don't use antialiasing to speed up line drawing, but use a width that scales with
# viewport scale to keep the line easily readable on hiDPI displays.
gpu_graph.draw_polyline(gpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
func _process(_delta: float) -> void:
if visible:
fps_graph.queue_redraw()
total_graph.queue_redraw()
cpu_graph.queue_redraw()
gpu_graph.queue_redraw()
# Difference between the last two rendered frames in milliseconds.
var frametime := (Time.get_ticks_usec() - last_tick) * 0.001
frame_history_total.push_back(frametime)
if frame_history_total.size() > HISTORY_NUM_FRAMES:
frame_history_total.pop_front()
# Frametimes are colored following FPS logic (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
# This makes the color gradient non-linear.
frametime_avg = frame_history_total.reduce(sum_func) / frame_history_total.size()
frame_history_total_avg.text = str(frametime_avg).pad_decimals(2)
frame_history_total_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_min: float = frame_history_total.min()
frame_history_total_min.text = str(frametime_min).pad_decimals(2)
frame_history_total_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_max: float = frame_history_total.max()
frame_history_total_max.text = str(frametime_max).pad_decimals(2)
frame_history_total_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
frame_history_total_last.text = str(frametime).pad_decimals(2)
frame_history_total_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var viewport_rid := get_viewport().get_viewport_rid()
var frametime_cpu := RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu()
frame_history_cpu.push_back(frametime_cpu)
if frame_history_cpu.size() > HISTORY_NUM_FRAMES:
frame_history_cpu.pop_front()
frametime_cpu_avg = frame_history_cpu.reduce(sum_func) / frame_history_cpu.size()
frame_history_cpu_avg.text = str(frametime_cpu_avg).pad_decimals(2)
frame_history_cpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_cpu_min: float = frame_history_cpu.min()
frame_history_cpu_min.text = str(frametime_cpu_min).pad_decimals(2)
frame_history_cpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_cpu_max: float = frame_history_cpu.max()
frame_history_cpu_max.text = str(frametime_cpu_max).pad_decimals(2)
frame_history_cpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
frame_history_cpu_last.text = str(frametime_cpu).pad_decimals(2)
frame_history_cpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_gpu := RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid)
frame_history_gpu.push_back(frametime_gpu)
if frame_history_gpu.size() > HISTORY_NUM_FRAMES:
frame_history_gpu.pop_front()
frametime_gpu_avg = frame_history_gpu.reduce(sum_func) / frame_history_gpu.size()
frame_history_gpu_avg.text = str(frametime_gpu_avg).pad_decimals(2)
frame_history_gpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_gpu_min: float = frame_history_gpu.min()
frame_history_gpu_min.text = str(frametime_gpu_min).pad_decimals(2)
frame_history_gpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
var frametime_gpu_max: float = frame_history_gpu.max()
frame_history_gpu_max.text = str(frametime_gpu_max).pad_decimals(2)
frame_history_gpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
frame_history_gpu_last.text = str(frametime_gpu).pad_decimals(2)
frame_history_gpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
frames_per_second = 1000.0 / frametime_avg
fps_history.push_back(frames_per_second)
if fps_history.size() > HISTORY_NUM_FRAMES:
fps_history.pop_front()
fps.text = str(floor(frames_per_second)) + " FPS"
var frame_time_color := frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
fps.modulate = frame_time_color
frame_time.text = str(frametime).pad_decimals(2) + " mspf"
frame_time.modulate = frame_time_color
var vsync_string := ""
match DisplayServer.window_get_vsync_mode():
DisplayServer.VSYNC_ENABLED:
vsync_string = "V-Sync"
DisplayServer.VSYNC_ADAPTIVE:
vsync_string = "Adaptive V-Sync"
DisplayServer.VSYNC_MAILBOX:
vsync_string = "Mailbox V-Sync"
if Engine.max_fps > 0 or OS.low_processor_usage_mode:
# Display FPS cap determined by `Engine.max_fps` or low-processor usage mode sleep duration
# (the lowest FPS cap is used).
var low_processor_max_fps := roundi(1000000.0 / OS.low_processor_usage_mode_sleep_usec)
var fps_cap := low_processor_max_fps
if Engine.max_fps > 0:
fps_cap = mini(Engine.max_fps, low_processor_max_fps)
frame_time.text += " (cap: " + str(fps_cap) + " FPS"
if not vsync_string.is_empty():
frame_time.text += " + " + vsync_string
frame_time.text += ")"
else:
if not vsync_string.is_empty():
frame_time.text += " (" + vsync_string + ")"
frame_number.text = "Frame: " + str(Engine.get_frames_drawn())
last_tick = Time.get_ticks_usec()
func _on_visibility_changed() -> void:
if visible:
# Reset graphs to prevent them from looking strange before `HISTORY_NUM_FRAMES` frames
# have been drawn.
var frametime_last := (Time.get_ticks_usec() - last_tick) * 0.001
fps_history.resize(HISTORY_NUM_FRAMES)
fps_history.fill(1000.0 / frametime_last)
frame_history_total.resize(HISTORY_NUM_FRAMES)
frame_history_total.fill(frametime_last)
frame_history_cpu.resize(HISTORY_NUM_FRAMES)
var viewport_rid := get_viewport().get_viewport_rid()
frame_history_cpu.fill(RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu())
frame_history_gpu.resize(HISTORY_NUM_FRAMES)
frame_history_gpu.fill(RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid))

View File

@@ -0,0 +1,402 @@
[gd_scene load_steps=3 format=3 uid="uid://cggqb75a8w8r"]
[ext_resource type="Script" path="res://addons/debug_menu/debug_menu.gd" id="1_p440y"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ki0n8"]
bg_color = Color(0, 0, 0, 0.25098)
[node name="CanvasLayer" type="CanvasLayer"]
process_mode = 3
layer = 128
[node name="DebugMenu" type="Control" parent="." node_paths=PackedStringArray("fps", "frame_time", "frame_number", "frame_history_total_avg", "frame_history_total_min", "frame_history_total_max", "frame_history_total_last", "frame_history_cpu_avg", "frame_history_cpu_min", "frame_history_cpu_max", "frame_history_cpu_last", "frame_history_gpu_avg", "frame_history_gpu_min", "frame_history_gpu_max", "frame_history_gpu_last", "fps_graph", "total_graph", "cpu_graph", "gpu_graph", "information", "settings")]
custom_minimum_size = Vector2(400, 400)
layout_mode = 3
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -416.0
offset_top = 8.0
offset_right = -16.0
offset_bottom = 408.0
grow_horizontal = 0
size_flags_horizontal = 8
size_flags_vertical = 4
mouse_filter = 2
script = ExtResource("1_p440y")
fps = NodePath("VBoxContainer/FPS")
frame_time = NodePath("VBoxContainer/FrameTime")
frame_number = NodePath("VBoxContainer/FrameNumber")
frame_history_total_avg = NodePath("VBoxContainer/FrameTimeHistory/TotalAvg")
frame_history_total_min = NodePath("VBoxContainer/FrameTimeHistory/TotalMin")
frame_history_total_max = NodePath("VBoxContainer/FrameTimeHistory/TotalMax")
frame_history_total_last = NodePath("VBoxContainer/FrameTimeHistory/TotalLast")
frame_history_cpu_avg = NodePath("VBoxContainer/FrameTimeHistory/CPUAvg")
frame_history_cpu_min = NodePath("VBoxContainer/FrameTimeHistory/CPUMin")
frame_history_cpu_max = NodePath("VBoxContainer/FrameTimeHistory/CPUMax")
frame_history_cpu_last = NodePath("VBoxContainer/FrameTimeHistory/CPULast")
frame_history_gpu_avg = NodePath("VBoxContainer/FrameTimeHistory/GPUAvg")
frame_history_gpu_min = NodePath("VBoxContainer/FrameTimeHistory/GPUMin")
frame_history_gpu_max = NodePath("VBoxContainer/FrameTimeHistory/GPUMax")
frame_history_gpu_last = NodePath("VBoxContainer/FrameTimeHistory/GPULast")
fps_graph = NodePath("VBoxContainer/FPSGraph/Graph")
total_graph = NodePath("VBoxContainer/TotalGraph/Graph")
cpu_graph = NodePath("VBoxContainer/CPUGraph/Graph")
gpu_graph = NodePath("VBoxContainer/GPUGraph/Graph")
information = NodePath("VBoxContainer/Information")
settings = NodePath("VBoxContainer/Settings")
[node name="VBoxContainer" type="VBoxContainer" parent="DebugMenu"]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -300.0
offset_bottom = 374.0
grow_horizontal = 0
mouse_filter = 2
theme_override_constants/separation = 0
[node name="FPS" type="Label" parent="DebugMenu/VBoxContainer"]
modulate = Color(0, 1, 0, 1)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 5
theme_override_constants/line_spacing = 0
theme_override_font_sizes/font_size = 18
text = "60 FPS"
horizontal_alignment = 2
[node name="FrameTime" type="Label" parent="DebugMenu/VBoxContainer"]
modulate = Color(0, 1, 0, 1)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "16.67 mspf (cap: 123 FPS + Adaptive V-Sync)"
horizontal_alignment = 2
[node name="FrameNumber" type="Label" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Frame: 1234"
horizontal_alignment = 2
[node name="FrameTimeHistory" type="GridContainer" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 8
mouse_filter = 2
theme_override_constants/h_separation = 0
theme_override_constants/v_separation = 0
columns = 5
[node name="Spacer" type="Control" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(60, 0)
layout_mode = 2
mouse_filter = 2
[node name="AvgHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Average"
horizontal_alignment = 2
[node name="MinHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Best"
horizontal_alignment = 2
[node name="MaxHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Worst"
horizontal_alignment = 2
[node name="LastHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Last"
horizontal_alignment = 2
[node name="TotalHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Total:"
horizontal_alignment = 2
[node name="TotalAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="TotalMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="TotalMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="TotalLast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="CPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "CPU:"
horizontal_alignment = 2
[node name="CPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="CPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "12.34"
horizontal_alignment = 2
[node name="CPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="CPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="GPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "GPU:"
horizontal_alignment = 2
[node name="GPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="GPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "1.23"
horizontal_alignment = 2
[node name="GPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="GPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "123.45"
horizontal_alignment = 2
[node name="FPSGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
alignment = 2
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/FPSGraph"]
custom_minimum_size = Vector2(0, 27)
layout_mode = 2
size_flags_horizontal = 8
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "FPS: ↑"
vertical_alignment = 1
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/FPSGraph"]
custom_minimum_size = Vector2(150, 25)
layout_mode = 2
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
[node name="TotalGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
alignment = 2
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/TotalGraph"]
custom_minimum_size = Vector2(0, 27)
layout_mode = 2
size_flags_horizontal = 8
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Total: ↓"
vertical_alignment = 1
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/TotalGraph"]
custom_minimum_size = Vector2(150, 25)
layout_mode = 2
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
[node name="CPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
alignment = 2
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/CPUGraph"]
custom_minimum_size = Vector2(0, 27)
layout_mode = 2
size_flags_horizontal = 8
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "CPU: ↓"
vertical_alignment = 1
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/CPUGraph"]
custom_minimum_size = Vector2(150, 25)
layout_mode = 2
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
[node name="GPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
layout_mode = 2
mouse_filter = 2
alignment = 2
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/GPUGraph"]
custom_minimum_size = Vector2(0, 27)
layout_mode = 2
size_flags_horizontal = 8
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "GPU: ↓"
vertical_alignment = 1
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/GPUGraph"]
custom_minimum_size = Vector2(150, 25)
layout_mode = 2
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
[node name="Information" type="Label" parent="DebugMenu/VBoxContainer"]
modulate = Color(1, 1, 1, 0.752941)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "12th Gen Intel(R) Core(TM) i0-1234K
Windows 12 64-bit (double precision), Vulkan 1.2.34
NVIDIA GeForce RTX 1234, 123.45.67"
horizontal_alignment = 2
[node name="Settings" type="Label" parent="DebugMenu/VBoxContainer"]
modulate = Color(0.8, 0.84, 1, 0.752941)
layout_mode = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 3
theme_override_font_sizes/font_size = 12
text = "Project Version: 1.2.3
Rendering Method: Forward+
Window: 1234×567, Viewport: 1234×567
3D Scale (FSR 1.0): 100% = 1234×567
3D Antialiasing: TAA + 2× MSAA + FXAA
SSR: 123 Steps
SSAO: On
SSIL: On
SDFGI: 1 Cascades
Glow: On
Volumetric Fog: On
2D Antialiasing: 2× MSAA"
horizontal_alignment = 2
[connection signal="visibility_changed" from="DebugMenu" to="DebugMenu" method="_on_visibility_changed"]

View File

@@ -0,0 +1,7 @@
[plugin]
name="Debug Menu"
description="In-game debug menu displaying performance metrics and hardware information"
author="Calinou"
version="1.1.2"
script="plugin.gd"

View File

@@ -0,0 +1,29 @@
@tool
extends EditorPlugin
func _enter_tree() -> void:
add_autoload_singleton("DebugMenu", "res://addons/debug_menu/debug_menu.tscn")
# FIXME: This appears to do nothing.
# if not ProjectSettings.has_setting("application/config/version"):
# ProjectSettings.set_setting("application/config/version", "1.0.0")
#
# ProjectSettings.set_initial_value("application/config/version", "1.0.0")
# ProjectSettings.add_property_info({
# name = "application/config/version",
# type = TYPE_STRING,
# })
#
# if not InputMap.has_action("cycle_debug_menu"):
# InputMap.add_action("cycle_debug_menu")
# var event := InputEventKey.new()
# event.keycode = KEY_F3
# InputMap.action_add_event("cycle_debug_menu", event)
#
# ProjectSettings.save()
func _exit_tree() -> void:
remove_autoload_singleton("DebugMenu")
# Don't remove the project setting's value and input map action,
# as the plugin may be re-enabled in the future.

102
export_presets.cfg Normal file
View File

@@ -0,0 +1,102 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="C:/Users/Midnight/Desktop/export2/not_bar.exe"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name=""
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
[preset.1]
name="Linux/X11"
platform="Linux/X11"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="C:/Users/Midnight/Desktop/export2/not_bar.x86_64"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
[preset.1.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
binary_format/architecture="x86_64"
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="#!/usr/bin/env bash
export DISPLAY=:0
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
\"{temp_dir}/{exe_name}\" {cmd_args}"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""

1
icon.svg Normal file
View File

@@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>

After

Width:  |  Height:  |  Size: 950 B

37
icon.svg.import Normal file
View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b8fqumed5vu5w"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

BIN
luts/lut_saturated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@@ -0,0 +1,26 @@
[remap]
importer="3d_texture"
type="CompressedTexture3D"
uid="uid://bus418i6c6y3w"
path="res://.godot/imported/lut_saturated.png-bf0a35cafccb1516d07adffb4e04f5f3.ctex3d"
metadata={
"vram_texture": false
}
[deps]
source_file="res://luts/lut_saturated.png"
dest_files=["res://.godot/imported/lut_saturated.png-bf0a35cafccb1516d07adffb4e04f5f3.ctex3d"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
slices/horizontal=8
slices/vertical=8

41
prefabs/character.tscn Normal file
View File

@@ -0,0 +1,41 @@
[gd_scene load_steps=6 format=3 uid="uid://c4orppao35wg6"]
[ext_resource type="Script" path="res://src/character/character_controller.gd" id="1_2yciu"]
[ext_resource type="Script" path="res://src/character/physics_interpolate.gd" id="2_jbufo"]
[ext_resource type="Script" path="res://src/character/camera_controller.gd" id="3_i1tod"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_m1ch2"]
radius = 0.4
height = 1.8
[sub_resource type="CapsuleMesh" id="CapsuleMesh_64ysj"]
radius = 0.4
height = 1.8
[node name="Character" type="Node"]
[node name="Physics" type="CharacterBody3D" parent="."]
script = ExtResource("1_2yciu")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
shape = SubResource("CapsuleShape3D_m1ch2")
[node name="Visual" type="Node3D" parent="." node_paths=PackedStringArray("physicsObject")]
script = ExtResource("2_jbufo")
physicsObject = NodePath("../Physics")
[node name="CameraTarget" type="Node3D" parent="Visual"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.28439, 0)
[node name="CSGMesh3D" type="CSGMesh3D" parent="Visual"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
gi_mode = 0
mesh = SubResource("CapsuleMesh_64ysj")
[node name="CameraArm" type="Node3D" parent="." node_paths=PackedStringArray("target")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
script = ExtResource("3_i1tod")
target = NodePath("../Visual/CameraTarget")
[node name="Camera3D" type="Camera3D" parent="CameraArm"]

108
project.godot Normal file
View File

@@ -0,0 +1,108 @@
; 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="3D Character Controller Template"
config/version="0.0.2"
config/tags=PackedStringArray("3d")
run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.2", "Forward Plus")
boot_splash/bg_color=Color(0, 0, 0, 1)
config/icon="res://icon.svg"
[autoload]
DebugMenu="*res://addons/debug_menu/debug_menu.tscn"
GameManager="*res://src/game_manager.gd"
[display]
window/size/mode=4
[editor_plugins]
enabled=PackedStringArray("res://addons/debug_menu/plugin.cfg")
[input]
move_left={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
move_right={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
move_up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
move_down={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
jump={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
]
}
sprint={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null)
]
}
zoom_in={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
zoom_out={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
look_left={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":-1.0,"script":null)
]
}
look_right={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":1.0,"script":null)
]
}
look_up={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":-1.0,"script":null)
]
}
look_down={
"deadzone": 0.5,
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":1.0,"script":null)
]
}
[rendering]
lights_and_shadows/directional_shadow/16_bits=false
scaling_3d/mode=2
environment/defaults/default_clear_color=Color(0, 0, 0, 1)
environment/defaults/default_environment="res://scenes/main/main_environment.tres"

8
readme.md Normal file
View File

@@ -0,0 +1,8 @@
# 3D Character Controller Template
A simple template to get started with 3D
## Features
- Performance menu addon (`F3`)
- First/Third person character controller with basic input maps

64
scenes/main.tscn Normal file
View File

@@ -0,0 +1,64 @@
[gd_scene load_steps=7 format=3 uid="uid://dgfh1lgxud87u"]
[ext_resource type="PackedScene" uid="uid://c4orppao35wg6" path="res://prefabs/character.tscn" id="2_v34ds"]
[ext_resource type="Script" path="res://src/spawner.gd" id="3_xxi2i"]
[sub_resource type="GDScript" id="GDScript_12xd3"]
script/source = "extends Node3D
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
"
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xxbnc"]
albedo_color = Color(0.266667, 0.145098, 0.0823529, 1)
[sub_resource type="PlaneMesh" id="PlaneMesh_uelfv"]
material = SubResource("StandardMaterial3D_xxbnc")
size = Vector2(50, 50)
[sub_resource type="BoxShape3D" id="BoxShape3D_vbj2x"]
size = Vector3(50, 1, 50)
[node name="Main" type="Node3D"]
script = SubResource("GDScript_12xd3")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.276457, -0.764665, 0.582116, 0.11662, 0.62794, 0.769474, -0.953924, -0.14484, 0.262774, 0, 0, 0)
light_energy = 2.0
shadow_enabled = true
directional_shadow_fade_start = 1.0
directional_shadow_max_distance = 50.0
[node name="Spawner" type="Node3D" parent="."]
script = ExtResource("3_xxi2i")
object_to_spawn = ExtResource("2_v34ds")
[node name="CSGMesh3D" type="CSGMesh3D" parent="."]
mesh = SubResource("PlaneMesh_uelfv")
[node name="StaticBody3D" type="StaticBody3D" parent="CSGMesh3D"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="CSGMesh3D/StaticBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
shape = SubResource("BoxShape3D_vbj2x")
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
use_collision = true
[node name="Box" type="CSGBox3D" parent="CSGCombiner3D"]
[node name="Box5" type="CSGBox3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.37539, 1.21157, -5.02753)
[node name="Box2" type="CSGBox3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0.5, 0.5)
[node name="Box4" type="CSGBox3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.06635, 1.17009, -1.15682)
size = Vector3(1, 1, 4.31364)
[node name="Box3" type="CSGBox3D" parent="CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.15636, 1.09924, 0.824171)
size = Vector3(3.28895, 0.716575, 1)

View File

@@ -0,0 +1,34 @@
[gd_resource type="Environment" load_steps=4 format=3 uid="uid://b8fqed8jo6yqj"]
[ext_resource type="CompressedTexture3D" uid="uid://bus418i6c6y3w" path="res://luts/lut_saturated.png" id="1_3f5y7"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_rxwic"]
sky_top_color = Color(0.317647, 0.415686, 0.643137, 1)
sky_horizon_color = Color(0.878431, 0.929412, 1, 1)
ground_bottom_color = Color(0.439216, 0.290196, 0.239216, 1)
ground_horizon_color = Color(0.988235, 0.890196, 0.823529, 1)
sun_angle_max = 0.0
sun_curve = 1e-05
[sub_resource type="Sky" id="Sky_wbc5y"]
sky_material = SubResource("ProceduralSkyMaterial_rxwic")
[resource]
background_mode = 2
sky = SubResource("Sky_wbc5y")
tonemap_mode = 2
tonemap_white = 6.0
ssao_enabled = true
ssao_ao_channel_affect = 1.0
sdfgi_use_occlusion = true
sdfgi_bounce_feedback = 0.9
glow_enabled = true
glow_levels/4 = 1.0
glow_levels/6 = 1.0
glow_levels/7 = 1.0
glow_blend_mode = 4
fog_sun_scatter = 0.5
fog_aerial_perspective = 0.9
volumetric_fog_albedo = Color(0.960784, 0.984314, 1, 1)
adjustment_enabled = true
adjustment_color_correction = ExtResource("1_3f5y7")

View File

@@ -0,0 +1,29 @@
extends Node3D
@export var target : Node3D
@onready var camera = $Camera3D
var lookInput : Vector2 = Vector2.ZERO
func _input(event):
if event is InputEventMouseMotion:
lookInput.x += event.relative.y
lookInput.y += event.relative.x
return
var zoom = .0
if event.is_action_released("zoom_in"):
zoom -= .2
if event.is_action_released("zoom_out"):
zoom += .2
camera.position.z = clamp(camera.position.z + zoom, 0, 4)
func _process(delta):
lookInput += Input.get_vector('look_left','look_right', 'look_down', 'look_up')
global_position = target.global_position
rotation.x = clamp(rotation.x - lookInput.x * delta * 0.3, PI*-0.48, PI*0.2)
rotation.y -= lookInput.y * delta * 0.3
lookInput = Vector2.ZERO

View File

@@ -0,0 +1,52 @@
extends CharacterBody3D
var input3D : Vector3
@export var SPEED = 1.4
@export var SPRINT_SPEED = 3.0
@export var JUMP_VELOCITY = 4.5
var speed = .0
@onready var camera : Camera3D = get_viewport().get_camera_3d()
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
func _ready():
process_priority = 2
func getCameraRelativeInput() -> Vector3 :
var cam_basis = camera.global_transform.basis
cam_basis.x.y = 0
cam_basis.x = cam_basis.x.normalized()
cam_basis.z.y = 0
cam_basis.z = cam_basis.z.normalized()
var input = Input.get_vector("move_left", "move_right", "move_up", "move_down")
var relativeInput = Vector3.ZERO
relativeInput += input.x * cam_basis.x
relativeInput += input.y * cam_basis.z
return relativeInput
func _physics_process(delta):
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
input3D = getCameraRelativeInput()
speed = SPEED + Input.get_action_strength("sprint") * SPRINT_SPEED
var direction = input3D.normalized()
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
look_at(direction + global_position)
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
move_and_slide()

View File

@@ -0,0 +1,28 @@
extends Node3D
@export var physicsObject : PhysicsBody3D
var physics_delta : float = 1
var target : Transform3D
var prev : Transform3D
func _ready():
target = physicsObject.global_transform
prev = physicsObject.global_transform
var d = 0
func _process(delta):
d += delta
var t = d / physics_delta
global_transform = prev.interpolate_with(target, t)
func _physics_process(delta):
physics_delta = delta
d = 0
global_transform = target
prev = target
target = physicsObject.global_transform

20
src/game_manager.gd Normal file
View File

@@ -0,0 +1,20 @@
extends Node
var pause_menu_res = preload('res://ui/pause_menu.tscn')
var pause_menu: PauseMenu
func _ready() -> void:
pause_menu = pause_menu_res.instantiate()
get_tree().root.add_child.call_deferred(pause_menu)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed('ui_cancel'):
pause_game(not get_tree().paused)
func quit_game():
get_tree().quit()
func pause_game(pause = true):
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if pause else Input.MOUSE_MODE_CAPTURED
get_tree().paused = pause
pause_menu.visible = pause

View File

@@ -0,0 +1,10 @@
shader_type canvas_item;
render_mode blend_disabled;
uniform float blur_amount : hint_range(0,5) = 5.0;
uniform vec4 tint : source_color = vec4(.5, .5, .5, 1.0);
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
void fragment() {
COLOR = textureLod(screen_texture, SCREEN_UV, blur_amount) * tint;
}

12
src/spawner.gd Normal file
View File

@@ -0,0 +1,12 @@
class_name Spawner extends Node3D
@export var object_to_spawn: PackedScene
@export var auto_spawn: bool = true
func _ready() -> void:
if auto_spawn:
spawn.call_deferred()
func spawn() -> void:
var object = object_to_spawn.instantiate()
get_parent_node_3d().add_child(object)

61
ui/pause_menu.tscn Normal file
View File

@@ -0,0 +1,61 @@
[gd_scene load_steps=4 format=3 uid="uid://dilbjuywlv0mc"]
[ext_resource type="Shader" path="res://src/shaders/ui/blur.gdshader" id="1_q1q1u"]
[ext_resource type="Script" path="res://ui/src/pause_menu.gd" id="1_qw2fh"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_dcwl4"]
shader = ExtResource("1_q1q1u")
shader_parameter/blur_amount = 3.0
shader_parameter/tint = Color(0.5, 0.5, 0.5, 1)
[node name="PauseMenu" type="Control"]
process_mode = 2
visible = false
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_qw2fh")
[node name="MainPanel" type="PanelContainer" parent="."]
material = SubResource("ShaderMaterial_dcwl4")
layout_mode = 1
anchors_preset = 13
anchor_left = 0.5
anchor_right = 0.5
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="MarginContainer" type="MarginContainer" parent="MainPanel"]
layout_mode = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 10
[node name="VBoxContainer" type="VBoxContainer" parent="MainPanel/MarginContainer"]
custom_minimum_size = Vector2(300, 0)
layout_mode = 2
alignment = 1
[node name="Label" type="Label" parent="MainPanel/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_type_variation = &"HeaderLarge"
text = "Paused"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ContinueButton" type="Button" parent="MainPanel/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "Continue"
[node name="QuitButton" type="Button" parent="MainPanel/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "Quit
"
[connection signal="pressed" from="MainPanel/MarginContainer/VBoxContainer/ContinueButton" to="." method="_on_continue"]
[connection signal="pressed" from="MainPanel/MarginContainer/VBoxContainer/QuitButton" to="." method="_on_quit"]

7
ui/src/pause_menu.gd Normal file
View File

@@ -0,0 +1,7 @@
class_name PauseMenu extends Node
func _on_continue() -> void:
GameManager.pause_game(false)
func _on_quit() -> void:
GameManager.quit_game()