refactor(M03): extract terrain chunk LOD planner

This commit is contained in:
2026-07-16 09:44:11 +04:00
parent aa21aafdfa
commit eb94cfc646
11 changed files with 436 additions and 28 deletions
+30 -26
View File
@@ -19,6 +19,8 @@ const ADT_TILE_COORDINATE_SCRIPT := preload("res://src/domain/coordinates/adt_ti
const ADT_TILE_LOCAL_POSITION_SCRIPT := preload("res://src/domain/coordinates/adt_tile_local_position.gd")
const RENDERED_GROUND_SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd")
const TERRAIN_QUALITY_MESH_CACHE_SCRIPT := preload("res://src/render/terrain/terrain_quality_mesh_cache.gd")
const TERRAIN_CHUNK_LOD_POLICY_SCRIPT := preload("res://src/render/terrain/terrain_chunk_lod_policy.gd")
const TERRAIN_CHUNK_LOD_PLANNER_SCRIPT := preload("res://src/render/terrain/terrain_chunk_lod_planner.gd")
const STREAMING_TARGET_PLANNER_SCRIPT := preload("res://src/render/streaming/streaming_target_planner.gd")
const STREAMING_TARGET_POLICY_SCRIPT := preload("res://src/render/streaming/streaming_target_policy.gd")
const RENDER_BUDGET_SCHEDULER_SCRIPT := preload("res://src/render/streaming/render_budget_scheduler.gd")
@@ -181,6 +183,7 @@ const QUALITY_HIGH := "High"
var _builder
var _streaming_target_planner := STREAMING_TARGET_PLANNER_SCRIPT.new()
var _terrain_chunk_lod_planner := TERRAIN_CHUNK_LOD_PLANNER_SCRIPT.new()
var _map_dir := ""
var _abs_map_dir := ""
var _wdt_info: Dictionary = {}
@@ -797,6 +800,8 @@ func _refresh_streaming_targets_at(focus_pos: Vector3, force: bool) -> void:
func _apply_streaming_target(wanted_tiles: Dictionary, retained_tiles: Dictionary, focus_pos: Vector3) -> void:
_last_focus_pos = focus_pos
var typed_focus_position = GODOT_WORLD_POSITION_SCRIPT.new(focus_pos.x, focus_pos.y, focus_pos.z)
var terrain_chunk_lod_policy = _create_terrain_chunk_lod_policy()
var filtered_load_queue: Array = []
for request in _tile_load_queue:
@@ -831,7 +836,7 @@ func _apply_streaming_target(wanted_tiles: Dictionary, retained_tiles: Dictionar
state["wanted"] = wanted
state["retained"] = retained
if wanted:
state["desired_lods"] = _compute_desired_lods(state, focus_pos)
state["desired_lods"] = _compute_desired_lods(state, typed_focus_position, terrain_chunk_lod_policy)
state["desired_tile_lod"] = -1 if not state["desired_lods"].is_empty() else _compute_desired_tile_lod(state, focus_pos)
state["desired_tile_lod_visible"] = _compute_desired_tile_lod_visible(state, focus_pos)
elif retained:
@@ -2492,7 +2497,16 @@ func _finalize_loaded_tile(request: Dictionary, data: Dictionary) -> void:
}
# Use _last_focus_pos — already set correctly for both editor and game.
state["desired_lods"] = _compute_desired_lods(state, _last_focus_pos)
var typed_focus_position = GODOT_WORLD_POSITION_SCRIPT.new(
_last_focus_pos.x,
_last_focus_pos.y,
_last_focus_pos.z
)
state["desired_lods"] = _compute_desired_lods(
state,
typed_focus_position,
_create_terrain_chunk_lod_policy()
)
state["desired_tile_lod"] = -1 if not state["desired_lods"].is_empty() else _compute_desired_tile_lod(state, _last_focus_pos)
state["desired_tile_lod_visible"] = _compute_desired_tile_lod_visible(state, _last_focus_pos)
_tile_states[key] = state
@@ -3045,33 +3059,23 @@ func _reset_terrain_root_children() -> void:
child.free()
func _compute_desired_lods(state: Dictionary, cam_pos: Vector3) -> Dictionary:
if not use_chunk_terrain_lods:
return {}
var desired := {}
func _compute_desired_lods(
state: Dictionary,
typed_focus_position: RefCounted,
terrain_chunk_lod_policy: RefCounted
) -> Dictionary:
var chunks: Array = state["data"].get("chunks", [])
return _terrain_chunk_lod_planner.plan(chunks, typed_focus_position, terrain_chunk_lod_policy)
var lod0_sq: float = (lod0_radius_chunks * CHUNK_SIZE) ** 2
var lod1_sq: float = (lod1_radius_chunks * CHUNK_SIZE) ** 2
var lod2_sq: float = (lod2_radius_chunks * CHUNK_SIZE) ** 2
for chunk_id in range(chunks.size()):
var chunk: Dictionary = chunks[chunk_id]
if chunk.is_empty():
continue
var origin: Vector3 = chunk.get("origin", Vector3.ZERO)
var center := origin + Vector3(CHUNK_SIZE * 0.5, 0.0, CHUNK_SIZE * 0.5)
var dx := center.x - cam_pos.x
var dz := center.z - cam_pos.z
var dist_sq := dx * dx + dz * dz
if dist_sq <= lod0_sq: desired[chunk_id] = 0
elif dist_sq <= lod1_sq: desired[chunk_id] = 1
elif dist_sq <= lod2_sq: desired[chunk_id] = 2
return desired
func _create_terrain_chunk_lod_policy() -> RefCounted:
return TERRAIN_CHUNK_LOD_POLICY_SCRIPT.new(
use_chunk_terrain_lods,
lod0_radius_chunks,
lod1_radius_chunks,
lod2_radius_chunks,
CHUNK_SIZE
)
func _runtime_load_tile_radius() -> int: