Terrain des sites de plongée : champ de hauteur authoré, Banc du Vigilant, formes variées et rendu sous-marin #4

Open
olix21 wants to merge 47 commits from olix21/worktree-terrain-site-zone1 AGit into main
pull from: olix21/worktree-terrain-site-zone1
2 changed files with 78 additions and 1 deletions
Showing only changes of commit 26f29ce14f - Show all commits

No files matched your search

+39 -1
View File
@@ -8,7 +8,7 @@ const SiteTerrainData = preload("res://game/domain/sites/site_terrain_data.gd")
const ZONE1_TERRAIN_PATH := "res://content/sites/zone1_vigilant_terrain.res"
const TEST_COUNT := 36
const TEST_COUNT := 40
var _failures: Array[String] = []
@@ -22,6 +22,7 @@ func _init() -> void:
_test_escarpment()
_test_outcrop()
_test_boulder_field()
_test_strata()
if _failures.is_empty():
print("Site baker unit tests: %d passed, 0 failed." % TEST_COUNT)
@@ -174,6 +175,43 @@ func _test_boulder_field() -> void:
_expect(stacked.elevation_delta(0.0, 0.0) <= 4.0 + 0.001, "overlapping boulders combine by maximum, not by sum")
func _test_strata() -> void:
# A 45 degree plane sampled every 0.5 m: four cells per 2 m layer.
var recipe := _small_recipe()
recipe.columns = 41
recipe.rows = 41
recipe.cell_size_m = 0.5
recipe.origin_x_m = -10.0
recipe.origin_z_m = -10.0
recipe.primitives.append(SiteTerrainBaker.SlopedPlane.new(30.0, 1.0, 0.0, 0.0, 0.0))
var plain := SiteTerrainBaker.bake(recipe)
recipe.modifiers.append(SiteTerrainBaker.Strata.new(2.0, 0.9, 20.0, 35.0, Vector2.ZERO, 0.0))
var terraced := SiteTerrainBaker.bake(recipe)
var flat_cells := 0
var riser_cells := 0
for column in range(5, 35):
var rise := terraced.elevations_m[terraced.index_of(column + 1, 20)] - terraced.elevations_m[terraced.index_of(column, 20)]
if rise < 0.1:
flat_cells += 1
elif rise > 0.9:
riser_cells += 1
_expect(flat_cells >= 8 and riser_cells >= 4, "strata turn a steep slope into ledges and risers (%d flat, %d risers)" % [flat_cells, riser_cells])
_expect(is_equal_approx(terraced.elevations_m[terraced.index_of(20, 20)], plain.elevations_m[plain.index_of(20, 20)]), "strata keep the layer boundaries where they were")
var flat := _small_recipe()
flat.primitives.append(SiteTerrainBaker.SlopedPlane.new(30.3, 0.0, 0.0, 0.0, 0.0))
flat.modifiers.append(SiteTerrainBaker.Strata.new(2.0, 0.9, 20.0, 35.0, Vector2.ZERO, 0.0))
var flat_data := SiteTerrainBaker.bake(flat)
_expect(is_equal_approx(flat_data.elevations_m[flat_data.index_of(10, 10)], -30.3), "strata leave flat ground alone")
var identity := _small_recipe()
identity.primitives.append(SiteTerrainBaker.SlopedPlane.new(30.0, 1.0, 0.0, 0.0, 0.0))
var before := SiteTerrainBaker.bake(identity)
identity.modifiers.append(SiteTerrainBaker.Strata.new(2.0, 0.0, 20.0, 35.0, Vector2.ZERO, 0.0))
var after := SiteTerrainBaker.bake(identity)
_expect(before.elevations_m == after.elevations_m, "sharpness 0 is the identity")
func _test_zone1_artefact_is_stable() -> void:
var versioned := load(ZONE1_TERRAIN_PATH) as SiteTerrainData
_expect(versioned != null, "versioned zone 1 terrain loads")
+39
View File
@@ -415,6 +415,45 @@ class Modifier extends RefCounted:
return elevation_m
## Quantises steep ground into horizontal ledges layer_height_m apart: the stratified
## walls of a canyon or cliff. Flat floors and summits are below minimum_slope_degrees and
## stay untouched; the effect is full from full_slope_degrees. sharpness 0 leaves the
## field unchanged, 1 cuts hard steps. radius_m 0 applies everywhere.
class Strata extends Modifier:
var layer_height_m: float
var sharpness: float
var centre: Vector2
var radius_m: float
var _minimum_tangent: float
var _full_tangent: float
func _init(
p_layer_height_m: float,
p_sharpness: float,
p_minimum_slope_degrees: float,
p_full_slope_degrees: float,
p_centre: Vector2,
p_radius_m: float
) -> void:
layer_height_m = p_layer_height_m
sharpness = clampf(p_sharpness, 0.0, 0.999)
centre = p_centre
radius_m = p_radius_m
_minimum_tangent = tan(deg_to_rad(p_minimum_slope_degrees))
_full_tangent = tan(deg_to_rad(p_full_slope_degrees))
func modify(x_m: float, z_m: float, elevation_m: float, gradient: Vector2) -> float:
var weight := smoothstep(_minimum_tangent, _full_tangent, gradient.length())
if radius_m > 0.0:
weight *= 1.0 - smoothstep(radius_m * 0.8, radius_m, Vector2(x_m, z_m).distance_to(centre))
if weight <= 0.0:
return elevation_m
var layer := floorf(elevation_m / layer_height_m)
var fraction := elevation_m / layer_height_m - layer
var sharpened := clampf((fraction - 0.5) / (1.0 - sharpness) + 0.5, 0.0, 1.0)
return lerpf(elevation_m, (layer + sharpened) * layer_height_m, weight)
class MaterialPatch extends RefCounted:
var centre: Vector2
var radius_m: float