Gateway Bridge: 64.5 m over the river, and a drag strip to match

The Sir Leo Hielscher Bridges and their industrial hinterland, from OSM
+ DEM like everything else -- but a 64.5 m concrete box girder split
across 13 OSM ways and twin carriageways broke every bridge assumption
the builder had, three different ways, before the right abstraction
appeared:

- Per-way sine humps (the Story Bridge recipe) turned each short
  approach span into a 52 m wall.
- A whole-bridge axis projection lifted named segments 3 km from the
  water and cliffed at every segment seam.
- The fix: deck height is a CONTINUOUS FIELD of distance-to-river --
  smoothstep from terrain to +57 m over the water. The river is the
  thing being bridged; let it set the profile. Seams are geometrically
  impossible because the field doesn't know what a segment is.

The bridge arg grew to Name:hump:style. Style "box" adds concrete
piers under every bridge-tagged span (28 of them), collision guardrails
chasing both deck edges (a 64 m deck with open edges is a cliff with
lane markings -- the first playtest fell off it), and puts Spawn,
DragStart/End and the RacePath on the deck field. Story Bridge keeps
its 16 m truss unchanged.

The payoff mode: a 1,422 m drag strip -- the longest in the game --
running up and over the bridge, verified in-shot racing Nanna's Morry
between the steel rails with the deck climbing ahead. Race mode's
auto-traced loop weaves interchange ramps and is honestly chaotic;
README flags the hand-authored-loop fix if bridge racing matters.

Plus the trace stitcher's loose-join pass (carriageways within 60 m
merge), a FLUX river-industrial sky, and the loose-join is what future
divided-road levels will lean on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-08-01 18:41:24 +10:00
parent 9844bee7ab
commit 939c2c5c35
58 changed files with 1328 additions and 10 deletions

View File

@ -373,6 +373,24 @@ asphalt (a summit lookout carpark is a burnout pad, not a dirt patch) and
tower stands over its carpark. Race is 3 laps of the mountain; the summit
carparks come pre-stocked with parked shitboxes.
### The Gateway (big-bridge support)
`gateway` is the Sir Leo Hielscher Bridges and their industrial hinterland.
Big concrete bridges taught the builder new tricks, all driven by the bridge
arg's new form `Name:hump:style` (Story Bridge stays `Bradfield Highway`,
16 m truss): the **box style** computes deck height as a continuous field from
**distance to the river** (smoothstep to +57 m over the water) — the Gateway
is 13 OSM ways across twin carriageways, and both a per-way hump and a
whole-bridge axis projection produced 52 m walls; the river being the thing
bridged is the only profile that can't seam. Concrete **piers** rise under
every bridge-tagged span, **guardrails** with collision chase the deck edges
(a 64 m deck with open edges is a cliff with lane markings), and the Spawn,
DragStart/End and RacePath markers all ride the deck field. The payoff: a
**1,422 m drag strip up and over the bridge** — the longest in the game — with
the ladder, tree and gearbox all live at altitude. Race mode's auto-traced
loop weaves the interchange ramps and is honestly chaotic; a hand-authored
carriageway loop is the known fix if bridge racing matters later.
### Cashies tool props (dealgod → TRELLIS)
`assets/tools/*.glb` are real secondhand-shop stock: photos pulled from the

BIN
levels/gateway/level.glb Normal file

Binary file not shown.

View File

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://p2kk5p7n3i56"
path="res://.godot/imported/level.glb-59ab952b0aa80b55d127c24ee93cf646.scn"
[deps]
source_file="res://levels/gateway/level.glb"
dest_files=["res://.godot/imported/level.glb-59ab952b0aa80b55d127c24ee93cf646.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ygrhg1yi3row"
path="res://.godot/imported/level_asphalt.jpg-6686877c276e4a7d387b981ef649012a.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "6d4e58bce08ad885d626807f4870dd6b"
}
[deps]
source_file="res://levels/gateway/level_asphalt.jpg"
dest_files=["res://.godot/imported/level_asphalt.jpg-6686877c276e4a7d387b981ef649012a.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dxn373g50iyh7"
path="res://.godot/imported/level_awning_cream.jpg-ae0a812958bfb924bae313ab5d9ba5ce.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "fd6eadc50ee05328df123d962ebcc1a2"
}
[deps]
source_file="res://levels/gateway/level_awning_cream.jpg"
dest_files=["res://.godot/imported/level_awning_cream.jpg-ae0a812958bfb924bae313ab5d9ba5ce.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b6yyox7xw1gp5"
path="res://.godot/imported/level_awning_green.jpg-d882422066cb6b8afcd827624e891784.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "5f02e613fa470f9c1aae51f038c294a8"
}
[deps]
source_file="res://levels/gateway/level_awning_green.jpg"
dest_files=["res://.godot/imported/level_awning_green.jpg-d882422066cb6b8afcd827624e891784.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bxype2vxqci5o"
path="res://.godot/imported/level_awning_grey.jpg-58a1fbe977c658a521347b94aa582999.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "3dbfb0d5f478755a1370246878836a74"
}
[deps]
source_file="res://levels/gateway/level_awning_grey.jpg"
dest_files=["res://.godot/imported/level_awning_grey.jpg-58a1fbe977c658a521347b94aa582999.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mrqco6irwje"
path="res://.godot/imported/level_bark.jpg-31551e36f2d4d2f2b91a104206b32625.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "21804a334d55f3bdba9fe0ac964afcd4"
}
[deps]
source_file="res://levels/gateway/level_bark.jpg"
dest_files=["res://.godot/imported/level_bark.jpg-31551e36f2d4d2f2b91a104206b32625.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cxp1atix7mm2d"
path="res://.godot/imported/level_billboard_ad.jpg-1876b6244d3a534ee4d89a62eab1e37c.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "5f8c3c138d0015a36f7939ed07d448d6"
}
[deps]
source_file="res://levels/gateway/level_billboard_ad.jpg"
dest_files=["res://.godot/imported/level_billboard_ad.jpg-1876b6244d3a534ee4d89a62eab1e37c.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mry8ck4uyajd"
path="res://.godot/imported/level_billboard_ad2.jpg-34b8d12797c794101454d1bddd6951b7.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "6c5a71b34b1df4b677d4e45bc19bfd6a"
}
[deps]
source_file="res://levels/gateway/level_billboard_ad2.jpg"
dest_files=["res://.godot/imported/level_billboard_ad2.jpg-34b8d12797c794101454d1bddd6951b7.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cf8oys06eh10y"
path="res://.godot/imported/level_billboard_ad3.jpg-7595a58fe75c0cbae77906ba69bc96ef.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "91e97464e5959aab2873019597cd6a55"
}
[deps]
source_file="res://levels/gateway/level_billboard_ad3.jpg"
dest_files=["res://.godot/imported/level_billboard_ad3.jpg-7595a58fe75c0cbae77906ba69bc96ef.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cd08ttva84yyi"
path="res://.godot/imported/level_concrete_ground.jpg-82ebde0bfb5cf985176032289238269c.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "da8e49ed928188692e8b27f94880d0f0"
}
[deps]
source_file="res://levels/gateway/level_concrete_ground.jpg"
dest_files=["res://.godot/imported/level_concrete_ground.jpg-82ebde0bfb5cf985176032289238269c.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bgqf20y1ypg48"
path="res://.godot/imported/level_facade_brick.jpg-d8ef2c2f559e3faf57b7470493ef4026.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "9bbc1f659c3ae0f8ff50415e0e25b0a0"
}
[deps]
source_file="res://levels/gateway/level_facade_brick.jpg"
dest_files=["res://.godot/imported/level_facade_brick.jpg-d8ef2c2f559e3faf57b7470493ef4026.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dkew67xa823kc"
path="res://.godot/imported/level_facade_concrete.jpg-1784d85c41566dbd0aac91d0112f4d75.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "01abc5a72c9b0db9fa03d6a8187d657e"
}
[deps]
source_file="res://levels/gateway/level_facade_concrete.jpg"
dest_files=["res://.godot/imported/level_facade_concrete.jpg-1784d85c41566dbd0aac91d0112f4d75.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bh3txxhdls552"
path="res://.godot/imported/level_facade_deco.jpg-67c56d2737631860a70ceef256aeb781.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "ada93740d168d1ff3a8c4613a7859fc4"
}
[deps]
source_file="res://levels/gateway/level_facade_deco.jpg"
dest_files=["res://.godot/imported/level_facade_deco.jpg-67c56d2737631860a70ceef256aeb781.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://duxxp11gr6ln6"
path="res://.godot/imported/level_facade_glass.jpg-c1ac96a5fc502aedd34cdfbf0c245aef.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "1e88904ab07ea05ef51b0ad5ef8a5176"
}
[deps]
source_file="res://levels/gateway/level_facade_glass.jpg"
dest_files=["res://.godot/imported/level_facade_glass.jpg-c1ac96a5fc502aedd34cdfbf0c245aef.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cv51rci5hhu7t"
path="res://.godot/imported/level_facade_glass2.jpg-c3b8c42cff72b2c117b0daac6ef149b7.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "09bf1228d59ce8eb5075472ecfafa796"
}
[deps]
source_file="res://levels/gateway/level_facade_glass2.jpg"
dest_files=["res://.godot/imported/level_facade_glass2.jpg-c3b8c42cff72b2c117b0daac6ef149b7.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bcjghephcir6h"
path="res://.godot/imported/level_facade_heritage.jpg-438e999eb241704e97f5c1089dc1dbdf.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "ba9e1709cb12bd8fdb4a19289f624abe"
}
[deps]
source_file="res://levels/gateway/level_facade_heritage.jpg"
dest_files=["res://.godot/imported/level_facade_heritage.jpg-438e999eb241704e97f5c1089dc1dbdf.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mvn6kahudvud"
path="res://.godot/imported/level_foliage.jpg-b1d98c42a1dd327edc11b935fcec1cd1.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "ab3257b92ff0b75b17ceb374a6bfe480"
}
[deps]
source_file="res://levels/gateway/level_foliage.jpg"
dest_files=["res://.godot/imported/level_foliage.jpg-b1d98c42a1dd327edc11b935fcec1cd1.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cq6nbbmrsq2ln"
path="res://.godot/imported/level_foliage_jacaranda.jpg-b72936de3a4f69572e89f35fdc88e17b.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "03eaf7e7939cd60d6eeae70a412aaa2a"
}
[deps]
source_file="res://levels/gateway/level_foliage_jacaranda.jpg"
dest_files=["res://.godot/imported/level_foliage_jacaranda.jpg-b72936de3a4f69572e89f35fdc88e17b.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://couluxhx6hovw"
path="res://.godot/imported/level_footpath.jpg-9f8aa1f7dba7ea4e2e9b3470229e25a2.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "7cbdf662fc4a640b776d7b1845d41e45"
}
[deps]
source_file="res://levels/gateway/level_footpath.jpg"
dest_files=["res://.godot/imported/level_footpath.jpg-9f8aa1f7dba7ea4e2e9b3470229e25a2.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dp5nlufyol6i0"
path="res://.godot/imported/level_grass.jpg-184b276dcbd05ac25c28bf7286afe123.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "01321994e4e9a94eb2f15dbe2978140b"
}
[deps]
source_file="res://levels/gateway/level_grass.jpg"
dest_files=["res://.godot/imported/level_grass.jpg-184b276dcbd05ac25c28bf7286afe123.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dk6fonqvl10a5"
path="res://.godot/imported/level_roof_deck.jpg-effc444ca55a919d90e47c0ec2f23947.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "abefe2c913e535b8e45c15c2fd64c035"
}
[deps]
source_file="res://levels/gateway/level_roof_deck.jpg"
dest_files=["res://.godot/imported/level_roof_deck.jpg-effc444ca55a919d90e47c0ec2f23947.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ljulk85wgtvh"
path="res://.godot/imported/level_sandstone.jpg-92531ea78d4695305bd6559b99074f96.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "4542fecfd809fc8ba6d5ffe37023980e"
}
[deps]
source_file="res://levels/gateway/level_sandstone.jpg"
dest_files=["res://.godot/imported/level_sandstone.jpg-92531ea78d4695305bd6559b99074f96.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cikv026qwos3u"
path="res://.godot/imported/level_shopfront.jpg-5f8f87e13bc8236714ec0ca51135f89b.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "54365d23c4a16f4093874e323505f747"
}
[deps]
source_file="res://levels/gateway/level_shopfront.jpg"
dest_files=["res://.godot/imported/level_shopfront.jpg-5f8f87e13bc8236714ec0ca51135f89b.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bcmt0jnj08vqn"
path="res://.godot/imported/level_signage_strip.jpg-591be2a71a659bcb8a7e953f7164cd3f.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "7bac04c3f15d3c6e34263659e61d8fe9"
}
[deps]
source_file="res://levels/gateway/level_signage_strip.jpg"
dest_files=["res://.godot/imported/level_signage_strip.jpg-591be2a71a659bcb8a7e953f7164cd3f.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://chvddpk3r606d"
path="res://.godot/imported/level_steel.jpg-e0572408174b419fa9e26cec20a2ad5c.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "c89cb67b55ae73418f6c5eae7ee0f6ca"
}
[deps]
source_file="res://levels/gateway/level_steel.jpg"
dest_files=["res://.godot/imported/level_steel.jpg-e0572408174b419fa9e26cec20a2ad5c.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=true
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dr3c1n2qgswrn"
path="res://.godot/imported/level_water.jpg-dbbe23ef57cc0347dd8b25b41f2bf01d.ctex"
metadata={
"vram_texture": false
}
generator_parameters={
"md5": "5c09ce05f3ec08d64ff6edccd71fef85"
}
[deps]
source_file="res://levels/gateway/level_water.jpg"
dest_files=["res://.godot/imported/level_water.jpg-dbbe23ef57cc0347dd8b25b41f2bf01d.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=true
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

BIN
levels/gateway/sky_day.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cykwpon5j1d2t"
path="res://.godot/imported/sky_day.jpg-ebc0287f7fa948751bd6248a6ba89548.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://levels/gateway/sky_day.jpg"
dest_files=["res://.godot/imported/sky_day.jpg-ebc0287f7fa948751bd6248a6ba89548.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

View File

@ -26,4 +26,5 @@ story_bridge|story_bridge.json|-27.4635|153.0355|Bradfield Highway|trace:Bradfie
kangaroo_point|kangaroo_point.json|-27.4780|153.0345|River Terrace|trace:River Terrace|-|-
mt_cootha|mt_cootha.json|-27.4735|152.9530|Sir Samuel Griffith Drive|trace:Sir Samuel Griffith Drive|-|-|grass
mt_gravatt|mt_gravatt.json|-27.5520|153.0755|Mount Gravatt Outlook Drive|trace:Mount Gravatt Outlook Drive|-|-|grass
gateway|gateway.json|-27.4470|153.1000|Gateway Motorway|trace:Gateway Motorway|Gateway Motorway:57:box|-|-
EOF

View File

@ -34,7 +34,14 @@ src, level_id = argv[0], argv[1]
LAT0, LON0 = float(argv[2]), float(argv[3])
spawn_arg = argv[4] if len(argv) > 4 else ""
rp_arg = argv[5] if len(argv) > 5 else ""
bridge_name = argv[6] if len(argv) > 6 and argv[6] != "-" else ""
# bridge arg: "Name" or "Name:hump_m" or "Name:hump_m:style" (truss|box).
# Story Bridge is "Bradfield Highway" (16 m hump, steel truss); the Gateway is
# "Gateway Motorway:52:box" -- a 64.5 m concrete box girder needs no cage.
_bridge_arg = argv[6] if len(argv) > 6 and argv[6] != "-" else ""
_bparts = _bridge_arg.split(":") if _bridge_arg else []
bridge_name = _bparts[0] if _bparts else ""
BRIDGE_HUMP = float(_bparts[1]) if len(_bparts) > 1 else 16.0
BRIDGE_STYLE = _bparts[2] if len(_bparts) > 2 else "truss"
canopy_name = argv[7] if len(argv) > 7 and argv[7] != "-" else ""
# 9th arg: raw-terrain texture. City levels keep concrete (urban ground between
# roads); "grass" also switches on forest fill -- bushland levels like Mt
@ -77,15 +84,49 @@ def H(x, y):
WATER_Z = 0.3 # river surface: above the riverbed's DEM zero, below banks
CARVE = [] # (x, y, h) of every draped road/path sample: terrain may not rise above these
_WATER_PTS = None # coarse point cloud of every water polygon
def _water_pts():
global _WATER_PTS
if _WATER_PTS is None:
_WATER_PTS = []
for e2 in d["elements"]:
t2 = e2.get("tags", {})
if (t2.get("natural") == "water" or t2.get("water")) and e2.get("geometry"):
geo = e2["geometry"]
for g in geo[::max(1, len(geo) // 80)]:
_WATER_PTS.append(xy(g["lat"], g["lon"]))
return _WATER_PTS
BRIDGE_R = 650.0 # how far from the water the big-deck climb begins
def named_deck_z(px4, py4):
"""Box-girder deck field: height rises with PROXIMITY TO THE RIVER, not
per way. OSM splits the Gateway into 13 ways across twin carriageways; a
per-way sine hump turned every short approach span into a 52 m wall, and
a whole-bridge axis projection lifted segments 3 km from the water. The
river is the thing being bridged -- let it set the profile: full hump over
the water, smoothstep down to terrain within BRIDGE_R, seam-free at every
segment boundary because the field is continuous in x,y."""
wp = _water_pts()
h = H(px4, py4)
if not wp:
return h
d2 = min((px4 - w[0]) ** 2 + (py4 - w[1]) ** 2 for w in wp)
t = 1.0 - min(math.sqrt(d2) / BRIDGE_R, 1.0)
s = t * t * (3.0 - 2.0 * t)
return max(h, h + BRIDGE_HUMP * s)
def bridge_profile(pts, named=False):
"""Deck heights for a bridge way: lerp between end terrain plus a hump, so
the deck spans the river instead of draping down into it."""
the deck spans the river instead of draping down into it. The named
bridge's hump comes from the arg (Story Bridge 16 m, Gateway 52 m)."""
cum = [0.0]
for i in range(1, len(pts)):
cum.append(cum[-1] + math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1]))
T = max(cum[-1], 0.001)
hA, hB = H(*pts[0]), H(*pts[-1])
hump = 16.0 if named else 3.5
hump = BRIDGE_HUMP if named else 3.5
return [max(H(*pts[i]),
hA + (hB - hA) * (cum[i] / T) + hump * math.sin(math.pi * cum[i] / T))
for i in range(len(pts))]
@ -737,7 +778,27 @@ for e in d["elements"]:
wide = ROAD_W.get(hw, 6.0)
rkey = "mall" if hw == "pedestrian" else ("bus" if hw == "busway" else "road")
deck = None
if tags.get("bridge") in ("yes", "viaduct") or (bridge_name and tags.get("name") == bridge_name):
if BRIDGE_STYLE == "box" and bridge_name and tags.get("name") == bridge_name:
# every named way, bridge-tagged or not: the field is continuous,
# so approach carriageways blend into the climb with no seams
deck = [named_deck_z(px4, py4) for (px4, py4) in pts]
# guardrails: a 64 m deck with open edges is a cliff with lane
# markings. Two low collision walls chase the deck edges.
rail = bmesh.new()
for i5 in range(len(pts) - 1):
(rx1, ry1), (rx2, ry2) = pts[i5], pts[i5 + 1]
rl = math.hypot(rx2 - rx1, ry2 - ry1)
if rl < 0.5:
continue
rnx, rny = -(ry2 - ry1) / rl, (rx2 - rx1) / rl
for rs in (-1.0, 1.0):
ox = rnx * rs * (wide / 2 - 0.2)
oy = rny * rs * (wide / 2 - 0.2)
beam(rail,
Vector((rx1 + ox, ry1 + oy, deck[i5] + 0.5)),
Vector((rx2 + ox, ry2 + oy, deck[i5 + 1] + 0.5)), 0.25, 1.0)
add_obj("bridge_rail_%d-col" % e["id"], rail, [M_STEEL], 4.0)
elif tags.get("bridge") in ("yes", "viaduct") or (bridge_name and tags.get("name") == bridge_name):
deck = bridge_profile(pts, named=(tags.get("name") == bridge_name))
ribbon(road_bm[rkey], pts, wide / 2, 0.03, zs=deck)
counts["road"] += 1
@ -912,7 +973,8 @@ if bridge_name:
s0, s1 = 0.175 * T, 0.825 * T
N = 26
bm = bmesh.new()
deck_zs = bridge_profile([(pp.x, pp.y) for pp in pts], named=True)
deck_zs = (bridge_profile([(pp.x, pp.y) for pp in pts], named=True)
if BRIDGE_STYLE == "truss" else [named_deck_z(pp.x, pp.y) for pp in pts])
def deck_at(sd):
for i2 in range(1, len(dists)):
if dists[i2] >= sd:
@ -945,8 +1007,55 @@ if bridge_name:
for i in range(0, N + 1, 3):
p, pe, h = samples[i]
beam(bm, p - pe * 8.0 + Vector((0, 0, h)), p + pe * 8.0 + Vector((0, 0, h)), 0.5, 0.5)
add_obj("bridge_steel-col", bm, [M_STEEL], 6.0)
print("bridge truss built along %r (%.0fm span)" % (bridge_name, s1 - s0))
if BRIDGE_STYLE == "truss":
add_obj("bridge_steel-col", bm, [M_STEEL], 6.0)
print("bridge truss built along %r (%.0fm span)" % (bridge_name, s1 - s0))
else:
bm.free()
if BRIDGE_STYLE == "box":
# concrete box-girder look: tall piers under EVERY bridge-tagged way
# of this name (both carriageways), from the ground/water up to the
# deck. The pier forest under a 64 m deck is the whole silhouette.
pier_bm = bmesh.new()
n_piers = 0
for e2 in d["elements"]:
t2 = e2.get("tags", {})
if t2.get("name") != bridge_name or not t2.get("bridge") or not e2.get("geometry"):
continue
bpts = [xy(g["lat"], g["lon"]) for g in e2["geometry"]]
if len(bpts) < 2:
continue
zs = [named_deck_z(px5, py5) for (px5, py5) in bpts]
bd = [0.0]
for i3 in range(1, len(bpts)):
bd.append(bd[-1] + math.hypot(bpts[i3][0] - bpts[i3 - 1][0],
bpts[i3][1] - bpts[i3 - 1][1]))
s = 40.0
while s < bd[-1] - 40.0:
for i3 in range(1, len(bd)):
if bd[i3] >= s:
f3 = (s - bd[i3 - 1]) / max(bd[i3] - bd[i3 - 1], 0.001)
px3 = bpts[i3 - 1][0] + (bpts[i3][0] - bpts[i3 - 1][0]) * f3
py3 = bpts[i3 - 1][1] + (bpts[i3][1] - bpts[i3 - 1][1]) * f3
dz = zs[i3 - 1] + (zs[i3] - zs[i3 - 1]) * f3
gz = min(H(px3, py3), 0.5) if dz > 30.0 else H(px3, py3)
if dz - gz > 9.0:
res3 = bmesh.ops.create_cube(pier_bm, size=1.0)
bmesh.ops.scale(pier_bm, vec=(2.6, 6.5, dz - gz),
verts=res3["verts"])
ang = math.atan2(bpts[i3][1] - bpts[i3 - 1][1],
bpts[i3][0] - bpts[i3 - 1][0])
bmesh.ops.rotate(pier_bm, cent=(0, 0, 0),
matrix=Matrix.Rotation(ang, 3, "Z"),
verts=res3["verts"])
bmesh.ops.translate(pier_bm,
vec=(px3, py3, gz + (dz - gz) / 2.0),
verts=res3["verts"])
n_piers += 1
break
s += 85.0
add_obj("bridge_piers-col", pier_bm, [M_CARPARK], 10.0)
print("bridge piers built along %r (%d piers)" % (bridge_name, n_piers))
# Winged shade canopies along pedestrian ways whose name starts with the given
# one -- OSM splits Queen Street Mall into a 15 m stub named "Queen Street Mall"
@ -1137,7 +1246,8 @@ if best_run and best_run[0] >= 150.0:
yaw = math.atan2(p1[1] - p0[1], p1[0] - p0[0])
for nm, p in (("DragStart", p0), ("DragEnd", p1)):
emp = bpy.data.objects.new(nm, None)
emp.location = (p[0], p[1], H(p[0], p[1]) + 0.1)
dz2 = named_deck_z(p[0], p[1]) if BRIDGE_STYLE == "box" and bridge_name else H(p[0], p[1])
emp.location = (p[0], p[1], dz2 + 0.1)
emp.rotation_euler = (0, 0, yaw)
bpy.context.collection.objects.link(emp)
counts["drag_m"] = int(run)
@ -1146,7 +1256,8 @@ if spawn_arg:
slat, slon, sbear = [float(v) for v in spawn_arg.split(",")]
sx, sy = xy(slat, slon)
sp = bpy.data.objects.new("Spawn", None)
sp.location = (sx, sy, H(sx, sy) + 0.1)
spz = named_deck_z(sx, sy) if BRIDGE_STYLE == "box" and bridge_name else H(sx, sy)
sp.location = (sx, sy, spz + 0.1)
sp.rotation_euler = (0, 0, math.radians(-sbear))
bpy.context.collection.objects.link(sp)
@ -1157,7 +1268,11 @@ if rp_arg:
plat, plon = [float(v) for v in pair.split(",")]
px, py = xy(plat, plon)
emp = bpy.data.objects.new("RP_%02d" % i, None)
emp.location = (px, py, H(px, py) + 0.1)
# box-bridge levels: the race line rides the DECK field, not the
# terrain -- at terrain height the grid spawns in the riverbed with
# the deck 57 m overhead and the AI races the ferry route
rz = named_deck_z(px, py) if BRIDGE_STYLE == "box" and bridge_name else H(px, py)
emp.location = (px, py, rz + 0.1)
bpy.context.collection.objects.link(emp)
emp.parent = rp

View File

@ -100,6 +100,30 @@ if loop[0].startswith("trace:"):
segs.pop(i)
grew = True
break
# second pass: divided carriageways never share nodes, so exact-endpoint
# stitching leaves the twin deck behind. Join leftovers whose end lies
# within 60 m of the chain's ends -- a motorway loop closes up one
# carriageway and back down the other.
def _gd(a, b):
return math.hypot((a["lon"] - b["lon"]) * 111320 * math.cos(math.radians(a["lat"])),
(a["lat"] - b["lat"]) * M_LAT)
grew = True
while grew and segs:
grew = False
for i, s in enumerate(segs):
for rev in (False, True):
g = list(reversed(s["geo"])) if rev else list(s["geo"])
if _gd(g[0], chain["geo"][-1]) < 60.0:
chain["geo"] = chain["geo"] + g
elif _gd(g[-1], chain["geo"][0]) < 60.0:
chain["geo"] = g + chain["geo"]
else:
continue
segs.pop(i)
grew = True
break
if grew:
break
geo = chain["geo"]
# dense sampling: a mountain road sampled every 16th point cuts hairpins
# cross-country and grids the race start in a paddock