Alpine W-profile guardrails
The actual 20260915-221352-campaign/alps-01-pass0-view1.png was inspected before this change. Its roadside barrier reads as a flat grey plank. This iteration replaces only the visible Alpine story steelwork. It does not narrow the road, move a selected rail segment, add collision or change the rail-selection conditions.
AlpineGuardrails.cs adds a continuous 310 mm high pressed W profile with 84 mm depth and 3 mm sheet thickness. Thirteen cross-section points form two lobes, a recessed centre and folded edges. Both front and back faces are actual geometry with their own normals; an ordinary one-sided HDRP/Lit metallic material shades them. The existing HDRP metal family supplies restrained zinc and fastener finishes. No unrelated ground texture, emission, custom shader or new downloaded source is used. UVs follow metres along the rail and developed profile length.
Each original 5 m segment receives one open I-section post, support bracket, overlapping profiled splice and two hexagonal fastener heads. The original lower protection bar remains visible over its unchanged collision proxy. A six-step rolled return and end post finish each continuous run. Returns curl away from traffic and do not extend longitudinally beyond the original run endpoint.
Exact collision preservation
The original TrackRuntime.BuildRoadside rail Beam/Beam/Box and portal-support Box calls still execute unchanged into the original WorldBatches. Rail and portal meshes can share a batch because its key excludes the object name. After that batch is emitted, the new class disables only the newly emitted steel MeshRenderers which have MeshColliders. Their original MeshFilters, MeshColliders, source geometry, grouping and triangle ordering are retained. The new visual batch also includes identical portal-support boxes, so hiding a shared old renderer cannot remove the gantry from the picture.
All new geometry uses WorldBatches with collider=false. WorldMesh.Emit registers generated meshes with GeneratedWorldResources. New material instances use the existing MaterialLibrary cache. The implementation never mutates or replaces an old shared mesh.
Budget and CPU proof
- Per original 5 m rail segment: 212 visual triangles (52 W-profile, 52 splice, 48 post/bracket, 48 fasteners, 12 lower bar).
- Per continuous run: 672 additional triangles (two 312-triangle returns, one 48-triangle end post).
- Portal-support copies: 12 triangles each. No per-fastener, per-post or per-segment GameObject is created; geometry is batched by the existing 150 m cells and three material identities.
- Exact budget:
212 * selectedSegments + 672 * continuousRuns + 12 * portalSupports. Segment selection is the old selection; an unconditional upper bound remains2 * ceil(track.Length / 5)segments. - Runtime
ALPINE_GUARDRAILlog reports selected segments, runs, visual batches, vertices, triangles and retained original collision batches. It also rejects any accidental Collider on a new visual object.
Tools/Art/audit_alpine_guardrail.py reads the actual source cross-section and reconstructs both roadside orientations at -12/0/+12 degree banks, including an 8-degree turn and both rolled ends. It checks 4,056 triangles: no zero-area or reversed-normal triangle; minimum winding/normal dot is 0.99605. It verifies all four original collision-generating expressions remain present exactly once. Output: ArtSource/Alps/Guardrails/audit.json and the mathematical source diagram profile-proof.png.
Managed Runtime + Editor compilation passes: 95 + 22 C# files, zero warnings/errors. The CPU diagram and source checks are not Unity visual acceptance or a runtime collision test. Root must still inspect the same native view1, verify highlights and readable W shape, visible portal supports, absence of gaps at run joins, and the actual runtime budget log.