--- id: wiki-20260508-vr-sickness-redir title: VR Sickness category: 10_Wiki/Topics status: verified canonical_id: self aliases: [cybersickness, simulator sickness, VR motion sickness] duplicate_of: none source_trust_level: A confidence_score: 0.91 verification_status: applied tags: [vr, ux, perception, three-js] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript framework: Three.js / WebXR --- # VR Sickness ## 매 한 줄 > **"매 visual motion 과 vestibular 의 mismatch 의 motion sickness 의 trigger"**. 매 VR 의 가장 큰 UX 장벽 — 매 frame rate / FOV / locomotion 의 careful design 의 mitigation. 2026 의 Quest 3 / Vision Pro / PCVR 의 90Hz+ 의 default — 매 여전히 design pattern 의 핵심. ## 매 핵심 ### 매 원인 - **Sensory mismatch**: 매 eye 의 motion 의 perceive — 매 inner ear 의 stationary 의 report. - **Low frame rate**: <72fps 의 judder 의 sickness 의 trigger. - **Vection**: 매 large optical flow 의 self-motion 의 illusion. - **Latency**: motion-to-photon >20ms 의 mismatch 의 amplify. - **FOV motion**: peripheral 의 motion 의 sensitivity 가장 큼. ### 매 mitigation 기법 - **Teleport locomotion**: 매 smooth 대신 fade-to-black + jump. - **Tunnel vision (vignette)**: 매 motion 시 peripheral mask — 매 vection 감소. - **Snap turning**: 매 smooth rotation 대신 30° step. - **Comfort settings**: 매 user 의 individual tuning. - **High frame rate**: 90Hz+ 의 mandatory — Quest 3 의 default 90/120Hz. - **Stable horizon**: 매 cockpit / fixed reference frame. ### 매 응용 1. Beat Saber — 매 stationary play 의 zero motion sickness. 2. Half-Life Alyx — 매 teleport + smooth 의 toggle. 3. 매 자전거 simulator — 매 physical motion 의 real vestibular alignment. ## 💻 패턴 ### 매 Three.js + WebXR 의 framerate 의 monitor ```typescript import * as THREE from 'three'; const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.xr.enabled = true; let lastTime = performance.now(); renderer.setAnimationLoop((time) => { const dt = time - lastTime; if (dt > 14) console.warn(`Frame drop: ${dt.toFixed(1)}ms`); // 매 <72fps 의 경고 lastTime = time; renderer.render(scene, camera); }); ``` ### 매 Vignette 의 motion 시 적용 ```glsl // fragment shader uniform float u_vignetteStrength; varying vec2 vUv; void main() { vec2 center = vUv - 0.5; float dist = length(center); float vignette = smoothstep(0.5, 0.3 - u_vignetteStrength * 0.2, dist); gl_FragColor = vec4(color.rgb * vignette, 1.0); } ``` ```typescript // 매 movement 의 detect 후 strength 의 ramp const speed = velocity.length(); material.uniforms.u_vignetteStrength.value = THREE.MathUtils.clamp(speed / 5, 0, 0.6); ``` ### 매 Snap turn 의 implementation ```typescript let lastTurnTime = 0; const SNAP_ANGLE = Math.PI / 6; // 30° const COOLDOWN = 250; function update(controller: THREE.Group, input: GamepadAxes) { const now = performance.now(); if (Math.abs(input.thumbstickX) > 0.7 && now - lastTurnTime > COOLDOWN) { rig.rotation.y -= Math.sign(input.thumbstickX) * SNAP_ANGLE; lastTurnTime = now; fadeOutIn(50); // 매 brief blackout 의 ease } } ``` ### 매 Teleport locomotion ```typescript function teleport(targetPos: THREE.Vector3) { fadeToBlack(150).then(() => { rig.position.copy(targetPos); fadeFromBlack(150); }); } ``` ### 매 Stable horizon (cockpit reference) ```typescript // 매 vehicle simulator 의 cockpit mesh 의 always-visible const cockpit = new THREE.Mesh(cockpitGeo, cockpitMat); camera.add(cockpit); // 매 head 에 follow — 매 vestibular reference scene.add(camera); ``` ### 매 Comfort 설정 의 노출 ```typescript const settings = { movementType: 'teleport' as 'teleport' | 'smooth', vignetteEnabled: true, snapTurn: true, snapAngle: 30, }; // 매 in-game menu 의 user 노출 — 매 individual variance 의 대응 ``` ### 매 Latency 의 측정 ```typescript const xrSession = renderer.xr.getSession(); xrSession?.requestAnimationFrame((time, frame) => { // 매 frame.predictedDisplayTime - performance.now() = motion-to-photon }); ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Casual user | teleport + snap turn (default) | | Hardcore VR | smooth + comfort toggle | | Vehicle sim | cockpit + stable horizon | | Stationary game | minimal locomotion (Beat Saber) | | Motion ride | physical motion 의 sync | **기본값**: teleport + snap turn 의 default. 매 user toggle 의 expose. ## 🔗 Graph - 부모: [[Virtual Reality UX]] - 변형: [[VR 멀미 (VR Sickness)]] · [[VR 멀미(VR sickness)]] (Korean variants) - 응용: [[Beat Saber]] · [[가상현실(VR) 자전거 시뮬레이터]] - Adjacent: [[Vergence-Accommodation Conflicts]] · [[깊이 지각(Depth perception)]] · [[Edge Bleeding]] ## 🤖 LLM 활용 **언제**: VR app 의 design 의 comfort 권장, frame rate budget 의 explain, snap turn / teleport 의 trade-off. **언제 X**: 매 medical 진단 — 매 individual variance 의 큼 의 인지. ## ❌ 안티패턴 - **<72fps 의 ship**: 매 sickness 의 garantee. - **Smooth-only locomotion**: 매 casual user 의 alienate. - **Forced camera shake**: 매 vection 증폭. - **Unstable horizon**: 매 vehicle 의 wobble. ## 🧪 검증 / 중복 - Verified (Oculus VR Best Practices, Valve Half-Life Alyx postmortem). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — VR sickness FULL 작성 |