Skip to content

Implementation hole in terrain texture shaders results in visible texture shifts and graphical glitches #327

@gotmachine

Description

@gotmachine

Context

The terrain shaders for tiled detail textures are positioning the textures according to a global _floatingOriginOffset shader property. This Vector3 is set by the FloatingOrigin.TerrainShaderOffset, incremented by the offsetNonKrakensbane from every call to FloatingOrigin.setOffset(), in order to keep the texture position constant in world space as the origin is shifted.

Since this is a 32 bit float backed offset, it growing too large results in visual artifacts. The stock code avoid this resetting it it to zero in various cases when the terrain isn't visible to the player :

  • When the flight camera is deactivated, when switching to IVA or map view (
  • When the PQS terrain isn't visible anymore as the camera altitude is enough for only the scaled space mesh to be visible
  • When the terrain is out of the view frustrum
Image

Issues

There are multiple issues with all this :

  • This mean that the terrain detail textures position isn't deterministic at all, it changes when the player reload the game, switch between crafts or reload the same craft, goes in and out of IVA / map view, etc
  • There are cases where the offset is reset while the terrain is visible to the player :
    • Through the FloatingOrigin.OnCameraChange() callback on GameEvents.OnCameraChange, which can be fired when the camera didn't actually change, notably when hitting the "switch to IVA mode" key ("C") while the vessel is uncrewed, but there are likely other cases.
    • From Vessel.Update(), which is doing some buggy "terrain in view" check, resulting in the offset being reset while the PQS terrain is still visible (typically while in space a bit below the edge of the PQS/Scaledspace fadeout).
  • These are all opportunistic mechanisms, but there is no hard safeguard against the offset growing way too large, which will cause visual artifacts (pixelated terrain), and in practice this happen fairly often.

Example of hitting the "C" key repeatedly on an unmanned craft resulting in a texture shift :

2025-07-17.09-55-41-339.mp4

Example of traveling from the KSC to the nearby mountain range (top), and then going in/out of map view (bottom) resulting in non-persistent positioning of the detail textures :

Image

What to do about it

Ideally, the shaders would use a planet-relative double-backed offset, and then use it to compute a world-space offset in order to keep the tiled detail textures in the same place relative to the terrain. Since they don't, and that rewriting the shaders is a rabbit hole nobody will put their hands in, all we can do is set the global _floatingOriginOffset shader property more sensibly.

It isn't possible to use a planet-center relative offset without hitting floating-point precision related artifacts :

Image

Since the detail textures are tiled, an option could have been to recompute it every frame modulo the tiling size to keep the max range in check. Unfortunately, every texture is scaled differently and dynamically in the shader, so this isn't possible either (it would cause constant "sliding" of the textures).

In conclusion, making the textures position persistent and constant relative to the terrain is not feasible.

All we can do is mitigating the issues, and to do it better than stock :

  • Patch cases where the offset is reset while the terrain is visible. Likely, this can be achieved by bailing out when CameraManager.previousCameraMode is already Flight in the FloatingOrigin.OnCameraChange() callback.
  • Remove that weird "terrain in view" check in Vessel.Update() (why is this even running for every vessel instead of in a singleton ???)
  • Implement a check in the TerrainShaderOffset setter to reset it anyway when it goes to stupidly high values. We can maybe be a bit smart here, flagging that a reset needs to be done, then doing a proper "terrain in view" check every frame to avoid the texture shift from being (too) visible, but still enforcing a reset if the offset magnitude goes out of hand.

Related issues elswhere

Poodmund/Outer-Planets-Mod#55
Gameslinx/Parallax-Continued#56

Metadata

Metadata

Assignees

No one assigned

    Labels

    kspBugIdentified KSP issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions