feat: scale village queries and enrich Jajce center
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
extends Node3D
|
||||
|
||||
@export var terrain_path := NodePath("../../TerrainRoot/Terrain3D")
|
||||
@export var river_material: Material
|
||||
@export_range(6.0, 20.0, 0.5) var river_width := 8.0
|
||||
@export_range(2, 12, 1) var width_segments := 6
|
||||
@export_range(8, 96, 1) var length_segments := 36
|
||||
@export var local_start_z := -25.0
|
||||
@export var local_end_z := 40.0
|
||||
@export_range(0.05, 0.5, 0.01) var water_offset := 0.18
|
||||
|
||||
@onready var river_ribbon: MeshInstance3D = $RiverRibbon
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
call_deferred("_build_terrain_ribbon")
|
||||
|
||||
|
||||
func _build_terrain_ribbon() -> void:
|
||||
var terrain := get_node_or_null(terrain_path) as Terrain3D
|
||||
if terrain == null or terrain.data == null or river_material == null:
|
||||
push_warning("TerrainRiverRibbon: terrain or material is unavailable")
|
||||
return
|
||||
|
||||
var vertices := PackedVector3Array()
|
||||
var normals := PackedVector3Array()
|
||||
var uvs := PackedVector2Array()
|
||||
var indices := PackedInt32Array()
|
||||
var row_size := width_segments + 1
|
||||
for z_index in length_segments + 1:
|
||||
var progress := float(z_index) / float(length_segments)
|
||||
var local_z := lerpf(local_start_z, local_end_z, progress)
|
||||
var downstream_curve := smoothstep(0.58, 1.0, progress) * 12.0
|
||||
var center_offset := sin(progress * TAU) * 1.4 + downstream_curve
|
||||
var downstream_taper := lerpf(1.0, 0.45, smoothstep(0.65, 1.0, progress))
|
||||
var half_width := river_width * lerpf(0.52, 0.45, progress) * downstream_taper
|
||||
for x_index in width_segments + 1:
|
||||
var across := float(x_index) / float(width_segments)
|
||||
var local_x := center_offset + lerpf(-half_width, half_width, across)
|
||||
var world_sample := to_global(Vector3(local_x, 0.0, local_z))
|
||||
var terrain_height := terrain.data.get_height(world_sample)
|
||||
if is_nan(terrain_height):
|
||||
terrain_height = global_position.y
|
||||
vertices.append(
|
||||
to_local(Vector3(world_sample.x, terrain_height + water_offset, world_sample.z))
|
||||
)
|
||||
normals.append(Vector3.UP)
|
||||
uvs.append(Vector2(across, progress))
|
||||
|
||||
for z_index in length_segments:
|
||||
for x_index in width_segments:
|
||||
var top_left := z_index * row_size + x_index
|
||||
var top_right := top_left + 1
|
||||
var bottom_left := top_left + row_size
|
||||
var bottom_right := bottom_left + 1
|
||||
indices.append_array(
|
||||
[top_left, bottom_left, top_right, top_right, bottom_left, bottom_right]
|
||||
)
|
||||
|
||||
var arrays := []
|
||||
arrays.resize(Mesh.ARRAY_MAX)
|
||||
arrays[Mesh.ARRAY_VERTEX] = vertices
|
||||
arrays[Mesh.ARRAY_NORMAL] = normals
|
||||
arrays[Mesh.ARRAY_TEX_UV] = uvs
|
||||
arrays[Mesh.ARRAY_INDEX] = indices
|
||||
var mesh := ArrayMesh.new()
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
||||
mesh.surface_set_material(0, river_material)
|
||||
river_ribbon.mesh = mesh
|
||||
_align_pool_to_terrain(terrain)
|
||||
|
||||
|
||||
func _align_pool_to_terrain(terrain: Terrain3D) -> void:
|
||||
var pool := $PlungePool as MeshInstance3D
|
||||
var pool_sample := to_global(Vector3(pool.position.x, 0.0, pool.position.z))
|
||||
var pool_height := terrain.data.get_height(pool_sample)
|
||||
if is_nan(pool_height):
|
||||
return
|
||||
var local_surface := to_local(Vector3(pool_sample.x, pool_height + water_offset, pool_sample.z))
|
||||
for node_name in [&"PlungePool", &"FoamRing", &"FoamAtFall"]:
|
||||
var surface := get_node(NodePath(node_name)) as MeshInstance3D
|
||||
surface.position.y = local_surface.y
|
||||
Reference in New Issue
Block a user