# 5. Diegetic UI Approaches Part of [[UI Toolkit and Diegetic UI]]. Requires Unity 6000.5+. Previous: [[4.Data Binding and Custom Controls]]. Next: [[6.Diegetic Terminal and Wrist Display]]. ## 5.1 Vocabulary UI is classified by two questions: *does it exist in the game world?* and *do the characters know about it?* | Type | In world space | Known to the character | Example | |---|---|---|---| | Non-diegetic | No | No | Classic screen-space health bar, menu | | **Diegetic** | Yes | Yes | Ammo counter on the weapon, terminal on a wall, wrist computer, car dashboard | | Spatial | Yes | No | Floating enemy health bar, objective marker pinned in the world | | Meta | No | Yes | Blood on the screen, cracked visor | This tutorial's technical approaches cover both **diegetic** (terminal, wrist display) and **spatial** (anything in world space) UI. Technique does not decide the type; *fiction* does. Why choose it: immersion, no screen clutter, UI that is also a gameplay object (player has to walk to the terminal, look at the wrist). The costs: legibility depends on camera angle/distance, interaction needs a 3D pointer, and everything is tied to scene lighting and aspect. ## 5.2 The three implementation routes ### A. UI Toolkit -> `RenderTexture` -> mesh (screen on a prop) Render a UI Toolkit panel into a `RenderTexture` (`PanelSettings.targetTexture`) and use that texture on any material. Pointer input is **mapped manually** with `PanelSettings.SetScreenToPanelSpaceFunction`, usually by raycasting the screen and using the hit's UV (`RaycastHit.textureCoord`; requires a `MeshCollider`). - Works since UI Toolkit runtime exists; no World Space feature needed. - You control the shader/material: emission + bloom, CRT scanlines, curved glass, dirt, flicker, screen-off state, lit by the scene if you want. - Texture resolution is a fixed budget you control, independent of distance. - Cost: you write the input mapping; one RenderTexture per distinct screen (shared panel => shared texture). ### B. UI Toolkit World Space panels (flat panel hanging in 3D) Set `PanelSettings` **Render Mode = World Space** and place a `PanelRenderer` in the scene. It becomes a renderable object with a transform, sized by *Pixels Per Unit* and world-space size settings, rendered unlit, sorted by camera distance. Pointer input comes through **Panel Input Configuration** and colliders. - Fast to set up; input built in (event cameras, interaction layers, colliders). - Good for wrist displays, in-world labels, signs, holographic panels. - Limitations to design around (as documented for 6.2 and 6.3; confirm in 6000.5 notes): unlit by default; no depth-test control (it can draw through geometry unless you work around it, for example with a URP Render Objects feature or custom pass); no 2D sorting layers (sorts by camera distance); not for lighting-heavy "screen is a light" looks. Shader Graph custom UI shaders (6.3+, URP only) let you restyle but are not a scene-lighting integration. ### C. uGUI world-space Canvas `Canvas > Render Mode = World Space`, assign **Event Camera**, scale the `RectTransform` (typically 0.001 per pixel). Input goes through the standard `GraphicRaycaster` + `EventSystem`. - Mature, fully lit/depth-tested options, TextMeshPro, huge asset-store ecosystem. - Use it when you need what UI Toolkit world space lacks (depth testing, lit materials per Graphic, VR XR Interaction Toolkit's UI support). - Heavier GameObject hierarchy; layout is slower to author than UXML/USS. ## 5.3 Decision table | Need | Pick | |---|---| | Interactive screen on a prop that must look *physical* (glow, CRT, curved glass) | **A** render texture | | Flat panel anchored to a hand/object, mostly readouts | **B** world space panel | | Depth-tested UI (hides behind walls), lit UI, or XR Interaction Toolkit UI | **C** uGUI, or B with workaround | | Many identical floating health bars | B or C; profile (see [[7.UI Toolkit Pitfalls and Performance]]); consider non-UI sprites/meshes at scale | | Same UXML in several places (screen HUD + in-world copy) | A or B: reuse the UXML, give each its own `PanelSettings` | | Must work on a version before 6.2 | A or C | ## 5.4 Legibility rules (the part people skip) 1. **Design in physical size.** A screen 0.4 m wide viewed from 0.7 m: text needs to subtend roughly the same visual angle as a phone screen. Work backwards: pick a minimum body text of ~16-20 px **on a 1024 px-wide texture** and test at your intended viewing distance. 2. **High contrast, low density.** Diegetic panels are seen at angles, with bloom and lighting. Prefer big type, thick strokes, few elements. 3. **Use SDF/vector text** for world-space panels so text stays crisp when scaled. Apply mipmaps and anisotropic filtering to render textures (angled screens alias badly). 4. **Never show critical info only diegetically** unless that is the game's point; offer an accessibility option (HUD mirror or larger text). 5. **Give interaction a clear mode.** Look-at + press key -> "use mode" with free cursor and locked movement, rather than trying to aim FPS look and click tiny UI at once. 6. **Feedback**: hover highlights, key hints, audio. A 3D screen without hover feedback feels dead. ## 5.5 Interaction models | Model | How | Fits | |---|---|---| | Use mode | Press E at the prop; cursor unlocks; look/move disabled; mouse drives the panel; Esc exits | Terminals, kiosks, PC/console + mouse | | Crosshair click | Crosshair is the pointer; map the *screen center* ray to the panel; Interact key = click | FPS without cursor, gamepad | | Laser pointer | Ray from controller/hand | VR, world-space panels | | Direct touch | Finger collider overlaps the panel | VR | Section 6 uses **use mode** for the terminal. For gamepad/crosshair, return the screen-center position from your pointer source instead of the mouse position. ## 5.6 Keyboard focus, gameplay input and the cursor A diegetic text field has exactly the problems of an in-game chat box: - While a text field is focused, typed WASD must not move the player. Gate gameplay input with a single bool (`UIHasFocus`) or disable the player's action map while in use mode. - The mouse is probably locked to the screen center in FPS. Unlock and show it for use mode (`Cursor.lockState`, `Cursor.visible`), re-lock on exit. - Esc is both "leave use mode" and probably "pause": decide which has priority and consume the key in exactly one place. ## 5.7 Official references - World Space UI overview: https://docs.unity3d.com/6000.3/Documentation/Manual/ui-systems/world-space-ui.html - `PanelSettings.SetScreenToPanelSpaceFunction`: https://docs.unity3d.com/ScriptReference/UIElements.PanelSettings.SetScreenToPanelSpaceFunction.html (includes the UITextureProjection sample code) - Panel Settings properties reference: https://docs.unity.com/en-us/engine/7000.0/manual/uitoolkits/uielements/uie-support-for-runtime-ui/uie-render-runtime-ui/uie-runtime-panel-settings - `PanelSettings.targetTexture`: https://docs.unity3d.com/6000.3/Documentation/ScriptReference/UIElements.PanelSettings-targetTexture.html - Unity UI World Space Canvas: https://docs.unity3d.com/Packages/[email protected]/manual/class-Canvas.html Next: [[6.Diegetic Terminal and Wrist Display]].