Cliff faces: render visible vertical faces at steep terrain Z-steps (extends #239) #245
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo#245
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Extends #239 (the unfinished half: hillshade shipped in #242, cliff faces did not).
Problem
The ground is one continuous heightfield mesh with shared vertices, so a hard terrain
Z-step becomes a 1-cell-wide ramp, never a vertical face. In the fixed iso camera that ramp is
visible looking up-slope (its face toward the camera) but invisible from the opposite side;
combined with
maxStepZwalkability gating, a real step reads as an invisible wall / lag(owner-reported, correctly diagnosed as "the dislivello, with nothing showing it").
Goal
Render an explicit vertical rock/earth face at steep Z-steps so they read from every angle.
Client-rendering only —
maxStepZwalkability is already server-authoritative and correct;movement is unchanged.
Design (full spec in the branch)
docs/superpowers/specs/2026-08-01-cliff-faces-design.mdonfeat/cliff-faces.tiledata: new optionalcliffArtper terrain (string art id, default empty), positionalafter
baseZ. A cell draws its face with its own terrain's material; empty ⇒ no face.earth_cliff,stone_cliff,basalt_cliff,sandstone_cliff,frozen_cliff— each reused by several biomes. Briefs + target prompts inart/cliff/cliff-face-prompts.md(64×64 RGBA, seamless vertical tiling, one height = 16 Z).GroundBlendRenderer: at each camera-facing edge (E/S) whereΔZ ≥ CliffThreshold(default 8, above the ΔZ-5 coast step so coasts stay ramps), avertical quad from the neighbour's Z up to the cell's Z, UV tiled vertically.
Clifftechnique inground_blend.fx; per-material texture withAddressV = Wrap(no atlas — only ~5), top→bottom darkening + hillshade ambient. Drawn after the ground
(painter's), forward after the #243 composite.
CliffEdges), unit-tested.Invariants Check (critical-design-review)
✓cites the concrete element;N/Ais falsifiable. Full wording in the spec.maxStepZunchanged, server-side) · GM N/A ·Identity N/A · Protocol N/A (no wire/enum/DTO; derived client-side; no
ProtocolVersionbump) · String catalog N/A · Single-threaded sim N/A ·
World.csgate N/A ·Screengate ✓(logic in
CliffEdges+GroundBlendRenderer) · Engine-independence ✓ (CliffEdgesinClient.Core, MonoGame-free, tested) · Gameplay/Networking N/A · Act-on-instance N/A ·
Extend-by-type ✓ (new material = tiledata row + PNG, no runtime switch) · Typed
content-def ✓ (
cliffArtis an art id likelandArt→ string) · Server-paced N/A ·Persistence (GameServer) N/A · Persistence (Auth) N/A · Process separation N/A · Typed
options ✓ (
CliffThresholda render const likeSlopeScale, notGameOptions/IConfiguration)· Broadcasts/AoI N/A · Multi-platform ✓ (MonoGame + Client.Core, SM3) · Assets ✓
(real
art/cliff/*; missing ⇒ not drawn, no placeholder) · Asset naming ✓(
<material>_cliff, mirrored inuo-asset-map.md) · ModernUO ✓ (adopt "explicit face at aheight discontinuity"; diverge = mesh skirt, not a static sprite, to sit on the SDF heightfield)
· Docs & DoD ✓ (uo-asset-map + tiledata header + terrain-Z doc, this issue's DoD).
Definition of Done
tiledataparses optionalcliffArt(default empty); round-trip test; header comment updated.CliffEdges(Client.Core) unit-tested: emit on camera-facing step, no-emit below threshold,no-emit on N/W, and the tiling (
v>1) case.GroundZAt, via theClifftechnique after the ground, on both the deferred (#243) and single-pass paths, no topcrack, no coast-wide wall at the default threshold.
cliffArt; missing material/texture ⇒ no face (no crash/placeholder).art/cliff/cliff-face-prompts.md, baked intoassets.isoa, idsmirrored in
docs/uo-asset-map.md.angle, ≥ 2 materials.
Out of scope / follow-ups
Approach pivoted rock-textures → ambient occlusion. During the live visual gate, both rock-based approaches were rejected: vertical skirt faces show only S/E in the fixed iso camera (empty corners), and rock-textured slopes read as too artificial. The shipped solution darkens the foot of steep steps with a non-directional ambient-occlusion term folded into the existing hillshade (
TerrainOcclusion, Client.Core) — cliffs read as depth from every angle, no art. Design:docs/superpowers/specs/2026-08-01-cliff-ambient-occlusion-design.md. PR: #247.Marco aiutami invece di farti le unghie a tema pokemon 💅
Risolta via relief / cliff-rounding su main (#247 · #249). Le facce verticali letterali sono state scartate (in camera iso fissa lasciano angoli vuoti) — l'obiettivo (scogliere leggibili sui salti di Z) è raggiunto.