A small suggestion to script (refactor and usability improvement)
roalyr opened this issue · 3 comments
I'll leave it here just in case. don't want to poke you over this since Godot 4 has it covered, but still.
What's changed:
- Structured scene.
- Meshes are attached as children to
Scene_items
nodes, so no need to name them in any specific way. - LOD distances are relative, values are multiplied by the size of the parent node
LODs
- removed
get_children()
loop.
[gd_scene load_steps=2 format=2]
[sub_resource type="GDScript" id=1]
script/source = "# Copyright © 2020 Hugo Locurcio and contributors - MIT License
# See `LICENSE.md` included in the source distribution for details.
extends Spatial
# If `false`, LOD won't update anymore. This can be used for performance comparison
# purposes.
export var enable_lod = true
# The maximum LOD 0 (high quality) distance in units.
export var lod_0_relative_distance = 5
# The maximum LOD 1 (medium quality) distance in units.
export var lod_1_relative_distance = 25
# The maximum LOD 2 (low quality) distance in units.
# Past this distance, all LOD variants are hidden.
export var lod_2_relative_distance = 150
# The rate at which LODs will be updated (in seconds). Lower values are more reactive
# but use more CPU, which is especially noticeable with large amounts of LOD-enabled nodes.
# Set this accordingly depending on your camera movement speed.
# The default value should suit most projects already.
# Note: Slow cameras don't need to have LOD-enabled objects update their status often.
# This can overridden by setting the project setting `lod/refresh_rate`.
export var refresh_rate = 0.25
# The internal refresh timer.
var timer = 0.0
func _ready():
# Add random jitter to the timer to ensure LODs don't all swap at the same time.
randomize()
timer += rand_range(0, refresh_rate)
# Despite LOD not being related to physics, we chose to run in `_physics_process()`
# to minimize the amount of method calls per second (and therefore decrease CPU usage).
func _physics_process(delta):
if not enable_lod:
# Show
show_scenes(\"LOD0\")
# Hide
hide_scenes(\"LOD1\")
hide_scenes(\"LOD2\")
hide_scenes(\"LOD3\")
return
# We need a camera to do the rest.
var camera = get_viewport().get_camera()
if camera == null:
return
if timer <= refresh_rate:
timer += delta
return
timer = 0.0
var distance = camera.global_transform.origin.distance_to(global_transform.origin)
# The LOD level to choose (lower is more detailed).
# Multiply distance values by scale for relativism.
if distance < lod_0_relative_distance * self.scale.length():
# Show
show_scenes(\"LOD0\")
# Hide
hide_scenes(\"LOD1\")
hide_scenes(\"LOD2\")
hide_scenes(\"LOD3\")
elif distance < lod_1_relative_distance * self.scale.length():
# Show
show_scenes(\"LOD1\")
# Hide
hide_scenes(\"LOD2\")
hide_scenes(\"LOD0\")
hide_scenes(\"LOD3\")
elif distance < lod_2_relative_distance * self.scale.length():
# Show
show_scenes(\"LOD2\")
# Hide
hide_scenes(\"LOD1\")
hide_scenes(\"LOD0\")
hide_scenes(\"LOD3\")
else:
# Show
show_scenes(\"LOD3\")
# Hide
hide_scenes(\"LOD0\")
hide_scenes(\"LOD1\")
hide_scenes(\"LOD2\")
func show_scenes(lod_name):
self.get_node(lod_name).get_node(\"Scene_items\").show()
func hide_scenes(lod_name):
self.get_node(lod_name).get_node(\"Scene_items\").hide()
"
[node name="LODs" type="Spatial"]
script = SubResource( 1 )
__meta__ = {
"_editor_description_": "Do not rename or edit the nodes.
Put meshes into Scene Items nodes"
}
[node name="LOD0" type="Spatial" parent="."]
__meta__ = {
"_edit_lock_": true
}
[node name="Scene_items" type="Spatial" parent="LOD0"]
__meta__ = {
"_edit_lock_": true
}
[node name="LOD1" type="Spatial" parent="."]
__meta__ = {
"_edit_lock_": true
}
[node name="Scene_items" type="Spatial" parent="LOD1"]
__meta__ = {
"_edit_lock_": true
}
[node name="LOD2" type="Spatial" parent="."]
__meta__ = {
"_edit_lock_": true
}
[node name="Scene_items" type="Spatial" parent="LOD2"]
__meta__ = {
"_edit_lock_": true
}
[node name="LOD3" type="Spatial" parent="."]
__meta__ = {
"_edit_lock_": true
}
[node name="Scene_items" type="Spatial" parent="LOD3"]
__meta__ = {
"_edit_lock_": true
}
I'd prefer focusing on having people test #4 and make sure it works well in production, as it has a greater potential for performance optimization by using fewer script instances. Both your proposal and #4 will break compatibility, so it'll require bumping the version of this add-on to 2.0.0.
Note that LOD is slated to be implemented in 3.6 by godotengine/godot#53778, so this add-on may not be relevant anymore in the future.
I'd prefer focusing on having people test #4 and make sure it works well in production, as it has a greater potential for performance optimization by using fewer script instances. Both your proposal and #4 will break compatibility, so it'll require bumping the version of this add-on to 2.0.0.
Note that LOD is slated to be implemented in 3.6 by godotengine/godot#53778, so this add-on may not be relevant anymore in the future.
Oh, that would be great! Still might want to have a small wrapper script to automate LOD ranges absolute values (proportional to object scale).