--- id: wiki-2026-0508-vr-sickness title: VR Sickness category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Cybersickness, VR Motion Sickness, Simulator Sickness] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [vr, ux, perception, comfort] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: csharp framework: unity-xr --- # VR Sickness ## 매 한 줄 > **"매 vestibular system 매 시각-전정 mismatch 매 만들면 매 nausea 의 발생"**. 매 1990s simulator sickness 연구의 매 VR 확장 — 매 2026 매 Quest 3, Vision Pro, Pico 4 Ultra 매 90Hz+ / foveated rendering 으로 매 줄어들고 있지만 매 design choice (locomotion, FOV) 가 매 dominant factor. ## 매 핵심 ### 매 원인 (Sensory Conflict Theory) - **Visual-vestibular mismatch**: 눈은 movement 보지만 inner ear 는 stationary 신호 — 매 brain 의 "독 상태" 추정. - **Latency**: motion-to-photon > 20ms 매 sickness 급증. - **Low frame rate**: < 90Hz, 특히 dropped frame, 매 trigger. - **FOV manipulation**: peripheral vision movement 매 강한 vection. - **IPD mismatch**: 매 잘못된 inter-pupillary distance 매 eye strain → nausea. - **Acceleration in virtual locomotion**: 매 constant velocity OK, 매 acceleration 의 매 worst. ### 매 완화 기법 - **Teleport locomotion**: 매 smooth move 보다 매 sickness ~80% 감소. - **Tunneling / vignette**: peripheral 의 dark mask, vection 줄임. - **Snap turn**: smooth turn 대신 30~45° 매 step rotation. - **Static reference frame**: cockpit, helmet rim 등 매 fixed visual anchor. - **High refresh + reprojection**: 90Hz 이상 + ATW/ASW. - **Foveated rendering**: 매 GPU budget 매 free up → frame stability. ### 매 응용 1. Beat Saber: stationary play, 매 sickness rare. 2. Half-Life Alyx: teleport + smooth 양쪽 옵션, comfort slider. 3. Microsoft Flight Sim VR: cockpit anchor, 매 long-session OK. 4. No Man's Sky VR: smooth locomotion default — 매 highest sickness reports. ## 💻 패턴 ### Comfort vignette (Unity URP) ```csharp // 매 movement speed 매 따라 매 peripheral mask 매 강도 조절 using UnityEngine; using UnityEngine.Rendering.Universal; public class ComfortVignette : MonoBehaviour { [SerializeField] Vignette vignette; [SerializeField] CharacterController player; [SerializeField] float maxIntensity = 0.6f; void Update() { float speed = player.velocity.magnitude; float t = Mathf.Clamp01(speed / 4f); // 4 m/s 매 full vignette vignette.intensity.value = t * maxIntensity; } } ``` ### Snap turn input ```csharp public class SnapTurn : MonoBehaviour { [SerializeField] Transform xrRig; [SerializeField] float snapDegrees = 30f; [SerializeField] float deadzone = 0.7f; bool armed = true; void Update() { float x = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick).x; if (Mathf.Abs(x) < deadzone) { armed = true; return; } if (!armed) return; xrRig.Rotate(0, Mathf.Sign(x) * snapDegrees, 0); armed = false; } } ``` ### Teleport locomotion (XR Interaction Toolkit) ```csharp // 매 XRI 의 매 TeleportationProvider + arc raycaster 사용 using UnityEngine; using UnityEngine.XR.Interaction.Toolkit.Locomotion.Teleportation; public class TeleportTrigger : MonoBehaviour { [SerializeField] TeleportationProvider provider; public void RequestTeleport(Vector3 destination) { var req = new TeleportRequest { destinationPosition = destination, matchOrientation = MatchOrientation.WorldSpaceUp, }; provider.QueueTeleportRequest(req); } } ``` ### Frame timing budget check ```csharp // 매 frame budget 위반 매 detect — Quest 3 매 11.1ms@90Hz, 8.3ms@120Hz void LateUpdate() { float budget = 1f / Application.targetFrameRate; if (Time.unscaledDeltaTime > budget * 1.2f) { Debug.LogWarning($"Frame overran: {Time.unscaledDeltaTime*1000f:F1}ms"); } } ``` ### IPD calibration ```csharp // OpenXR 매 user IPD 매 read — 매 잘못 설정 매 nausea 의 hidden cause using UnityEngine.XR; float GetIpdMeters() { var head = InputDevices.GetDeviceAtXRNode(XRNode.Head); head.TryGetFeatureValue(CommonUsages.eyesData, out var eyes); var l = eyes.leftEye.position; var r = eyes.rightEye.position; return Vector3.Distance(l, r); } ``` ### Dynamic foveated rendering toggle (Quest 3) ```csharp // Quest 3 매 eye-tracked foveation — frame stability 의 강력한 도구 OVRManager.eyeTrackedFoveatedRenderingEnabled = true; OVRManager.foveatedRenderingLevel = OVRManager.FoveatedRenderingLevel.HighTop; ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Casual / first-time user | Teleport + snap turn default | | Action / FPS | Smooth + vignette + snap turn option | | Sim (flight, racing) | Cockpit anchor, smooth, 90Hz+ guaranteed | | Standing-only experience | 거의 sickness-free — Beat Saber model | | Seated narrative | Static camera + cuts, no virtual locomotion | **기본값**: Comfort menu 의 매 모든 option 매 expose — user 가 choose. ## 🔗 Graph - 변형: [[Cybersickness]] · [[Simulator Sickness]] ## 🤖 LLM 활용 **언제**: VR comfort design review, locomotion option 추천, frame budget 분석. **언제 X**: AR / pass-through 만 (vestibular conflict 적음), non-immersive VR / 360 video. ## ❌ 안티패턴 - **Forced smooth locomotion**: comfort option 의 X — 매 user churn. - **Cinematic camera shake**: VR 매 절대 X — 매 immediate nausea. - **Acceleration / deceleration smooth curve**: linear 보다 매 더 sick. - **Stuttering / dropped frames**: 60Hz 의 매 X — 매 90Hz minimum. - **High-altitude vertigo without snap**: 매 some users 매 panic + sickness. - **No comfort settings menu**: 2026 매 standard expectation. ## 🧪 검증 / 중복 - Verified (Oculus Best Practices 2025, Apple Vision Pro HIG, IEEE VR 2025 cybersickness papers). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — sensory conflict theory, mitigation patterns, Unity XR code |