diff --git a/content/sites/terrain_showcase.tres b/content/sites/terrain_showcase.tres new file mode 100644 index 0000000..d8a6035 --- /dev/null +++ b/content/sites/terrain_showcase.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" script_class="DiveSiteDefinition" format=3] + +[ext_resource type="Script" path="res://game/domain/sites/site_placement.gd" id="1_vfxru"] +[ext_resource type="Script" path="res://game/domain/sites/site_route.gd" id="2_eyncd"] +[ext_resource type="Script" path="res://game/domain/sites/dive_site_definition.gd" id="3_gsyse"] +[ext_resource type="Resource" path="res://content/sites/terrain_showcase_terrain.res" id="4_cdhpc"] + +[sub_resource type="Resource" id="Resource_1hr26"] +script = ExtResource("1_vfxru") +placement_id = &"vessel_anchor" +kind = 5 +position_m = Vector3(0, -16, 0) + +[resource] +script = ExtResource("3_gsyse") +site_id = &"terrain_showcase" +display_name = "Jardin des Formes" +terrain = ExtResource("4_cdhpc") +playable_bounds_m = Rect2(-220, -220, 440, 440) +spawn_position_m = Vector3(0, -12, 0) +placements = Array[ExtResource("1_vfxru")]([SubResource("Resource_1hr26")]) diff --git a/content/sites/terrain_showcase_terrain.res b/content/sites/terrain_showcase_terrain.res new file mode 100644 index 0000000..f97c88c Binary files /dev/null and b/content/sites/terrain_showcase_terrain.res differ diff --git a/docs/briefs/captures/terrain_showcase_terrain_preview.png b/docs/briefs/captures/terrain_showcase_terrain_preview.png new file mode 100644 index 0000000..7ec72f8 Binary files /dev/null and b/docs/briefs/captures/terrain_showcase_terrain_preview.png differ diff --git a/docs/briefs/captures/terrain_showcase_terrain_preview.png.import b/docs/briefs/captures/terrain_showcase_terrain_preview.png.import new file mode 100644 index 0000000..34d9476 --- /dev/null +++ b/docs/briefs/captures/terrain_showcase_terrain_preview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c448uwrxq3foi" +path="res://.godot/imported/terrain_showcase_terrain_preview.png-6c9dafd8892db2b24553477d0b6fc653.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/briefs/captures/terrain_showcase_terrain_preview.png" +dest_files=["res://.godot/imported/terrain_showcase_terrain_preview.png-6c9dafd8892db2b24553477d0b6fc653.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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 diff --git a/tools/bake_site_terrain.gd b/tools/bake_site_terrain.gd index 2b1bae3..c0b91f5 100644 --- a/tools/bake_site_terrain.gd +++ b/tools/bake_site_terrain.gd @@ -5,6 +5,7 @@ const SiteTerrainBaker = preload("res://tools/site_terrain_baker.gd") const RECIPES := { "vehicle_test": "res://tools/sites/vehicle_test_terrain_recipe.gd", "zone1_vigilant": "res://tools/sites/zone1_vigilant_recipe.gd", + "terrain_showcase": "res://tools/sites/terrain_showcase_recipe.gd", } const OUTPUT_DIRECTORY := "res://content/sites" const PREVIEW_DIRECTORY := "res://docs/briefs/captures" diff --git a/tools/sites/terrain_showcase_recipe.gd b/tools/sites/terrain_showcase_recipe.gd new file mode 100644 index 0000000..4908593 --- /dev/null +++ b/tools/sites/terrain_showcase_recipe.gd @@ -0,0 +1,112 @@ +extends RefCounted + +## Catalogue site « Jardin des Formes »: one quarter per reference landform +## (docs/briefs/terrain-varied-landforms.md §5). No wreck, no route; a single +## mooring beacon at the centre. Field 512 x 512 m at 1 m, +X east, +Z south. + +const SiteTerrainBaker = preload("res://tools/site_terrain_baker.gd") +const SiteTerrainData = preload("res://game/domain/sites/site_terrain_data.gd") +const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd") +const SitePlacement = preload("res://game/domain/sites/site_placement.gd") + +# North-west: stratified canyon cut through a mesa. +const MESA_CENTRE := Vector2(-120.0, -130.0) +const CANYON_PATH: Array[Vector2] = [ + Vector2(-205.0, -85.0), Vector2(-150.0, -120.0), Vector2(-110.0, -150.0), Vector2(-60.0, -200.0), +] +const CANYON_HALF_WIDTH_M := 14.0 +const CANYON_DEPTH_M := 20.0 +# North-east: crevasse between two buttes. +const WEST_BUTTE_CENTRE := Vector2(80.0, -120.0) +const EAST_BUTTE_CENTRE := Vector2(165.0, -125.0) +const CREVASSE_PATH: Array[Vector2] = [ + Vector2(122.0, -200.0), Vector2(118.0, -160.0), Vector2(124.0, -120.0), Vector2(119.0, -80.0), Vector2(123.0, -40.0), +] +const CREVASSE_HALF_WIDTH_M := 3.0 +const CREVASSE_DEPTH_M := 20.0 +# South-west: boulder field on rippled sand. +const BOULDER_FIELD_CENTRE := Vector2(-120.0, 110.0) +const BOULDER_FIELD_RADIUS_M := 75.0 +# South-east: two rock spurs framing a sand channel. +const WEST_SPUR_CENTRE := Vector2(80.0, 120.0) +const EAST_SPUR_CENTRE := Vector2(170.0, 125.0) +const CHANNEL_CENTRE := Vector2(125.0, 120.0) +# South: sinuous escarpment with rounded knolls on the slope below. +const ESCARPMENT_PATH: Array[Vector2] = [ + Vector2(-270.0, 215.0), Vector2(-150.0, 205.0), Vector2(-40.0, 225.0), Vector2(60.0, 205.0), + Vector2(170.0, 228.0), Vector2(270.0, 210.0), +] +const ESCARPMENT_DROP_M := 22.0 + + +static func recipe() -> SiteTerrainBaker.Recipe: + var result := SiteTerrainBaker.Recipe.new() + result.columns = 513 + result.rows = 513 + result.cell_size_m = 1.0 + result.origin_x_m = -256.0 + result.origin_z_m = -256.0 + result.floor_elevation_m = -80.0 + result.rock_slope_degrees = 20.0 + result.rock_reflectivity = 0.72 + result.sand_reflectivity = 0.45 + result.primitives = [ + # Base plateau: 30 m deep at the centre, 4 m deeper over the 500 m southward. + SiteTerrainBaker.SlopedPlane.new(30.0, 0.0, -0.008, 0.0, 0.0), + + # NW — la Mesa fendue: flat rock plateau 6 m high, 20 m deep canyon with a + # 14 m wide flat floor, 55 degree walls cut into 4 m ledges by the Strata + # modifier (one ledge every 2.8 m across, resolvable at 1 m per cell), rippled + # sand on the floor. + SiteTerrainBaker.Outcrop.new(MESA_CENTRE, 95.0, 85.0, 6.0, 10.0, 101, 6.0, true), + SiteTerrainBaker.Canyon.new(PackedVector2Array(CANYON_PATH), CANYON_HALF_WIDTH_M, CANYON_DEPTH_M, 7.0, 102, 2.0), + SiteTerrainBaker.Ripples.new(Vector2(0.8, -0.6), 4.0, 0.25, Vector2(-130.0, -140.0), 70.0), + + # NE — la Fente: two buttes 8-9 m high with a 6 m wide, 20 m deep slot between them. + SiteTerrainBaker.Outcrop.new(WEST_BUTTE_CENTRE, 38.0, 70.0, 8.0, 8.0, 201, 5.0, true), + SiteTerrainBaker.Outcrop.new(EAST_BUTTE_CENTRE, 38.0, 75.0, 9.0, 8.0, 202, 5.0, true), + SiteTerrainBaker.Canyon.new(PackedVector2Array(CREVASSE_PATH), CREVASSE_HALF_WIDTH_M, CREVASSE_DEPTH_M, 1.0, 203, 1.0), + + # SW — le Chaos: ninety boulders 2-6 m across plus six coral heads, on rippled sand. + SiteTerrainBaker.BoulderField.new(BOULDER_FIELD_CENTRE, BOULDER_FIELD_RADIUS_M, 301, 90, 2.0, 6.0, 0.7), + SiteTerrainBaker.BoulderField.new(Vector2(-100.0, 130.0), 40.0, 302, 6, 6.0, 9.0, 0.6), + SiteTerrainBaker.Ripples.new(Vector2(1.0, 0.3), 3.5, 0.3, BOULDER_FIELD_CENTRE, 110.0), + + # SE — les Éperons: two pitted rock spurs 6-7 m high framing a 20 m sand channel + # littered with small blocks. + SiteTerrainBaker.Outcrop.new(WEST_SPUR_CENTRE, 30.0, 60.0, 7.0, 5.0, 401, 7.0, true), + SiteTerrainBaker.Outcrop.new(EAST_SPUR_CENTRE, 30.0, 55.0, 6.0, 5.0, 402, 7.0, true), + SiteTerrainBaker.BoulderField.new(CHANNEL_CENTRE, 50.0, 403, 12, 1.5, 3.0, 0.8), + + # S — la Corniche: sinuous 22 m escarpment, then a 42 degree slope to the 80 m floor, + # with rounded knolls on the slope. + SiteTerrainBaker.Escarpment.new(PackedVector2Array(ESCARPMENT_PATH), ESCARPMENT_DROP_M, 6.0, 0.9, 501, 8.0), + SiteTerrainBaker.Outcrop.new(Vector2(-60.0, 240.0), 12.0, 10.0, 5.0, 10.0, 502, 2.0, true), + SiteTerrainBaker.Outcrop.new(Vector2(40.0, 236.0), 10.0, 9.0, 4.0, 9.0, 503, 2.0, true), + SiteTerrainBaker.Outcrop.new(Vector2(130.0, 245.0), 14.0, 11.0, 6.0, 11.0, 504, 2.0, true), + + # Roughness: broad undulation plus cell-scale pitting. + SiteTerrainBaker.Roughness.new(1933, 0.02, 0.6), + SiteTerrainBaker.Roughness.new(2027, 0.15, 0.2), + ] + result.modifiers = [ + # Strata on the mesa flanks and canyon walls only: 4 m ledges. + SiteTerrainBaker.Strata.new(4.0, 0.85, 30.0, 50.0, MESA_CENTRE, 130.0), + ] + return result + + +static func definition(terrain: SiteTerrainData) -> DiveSiteDefinition: + var result := DiveSiteDefinition.new() + result.site_id = &"terrain_showcase" + result.display_name = "Jardin des Formes" + result.terrain = terrain + result.playable_bounds_m = Rect2(-220.0, -220.0, 440.0, 440.0) + result.spawn_position_m = Vector3(0.0, -12.0, 0.0) + result.spawn_yaw_radians = 0.0 + var anchor := SitePlacement.new() + anchor.placement_id = &"vessel_anchor" + anchor.kind = SitePlacement.Kind.VESSEL_ANCHOR + anchor.position_m = Vector3(0.0, -16.0, 0.0) + result.placements = [anchor] + return result