--- id: wiki-2026-0508-안구-운동-기능-oculomotor-functions title: 안구 운동 기능 (Oculomotor functions) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Oculomotor, Eye Tracking, Gaze, Foveated Rendering Input] duplicate_of: none source_trust_level: B confidence_score: 0.85 verification_status: applied tags: [hci, eye-tracking, vr-ar, accessibility, foveated-rendering] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: webxr --- # 안구 운동 기능 (Oculomotor functions) ## 매 한 줄 > **"매 시선은 의도다"**. 사람의 안구 움직임 (saccade, smooth pursuit, fixation, vergence)은 attention과 intent의 신호 — HCI architecture에서 input modality, foveated rendering의 trigger, 그리고 accessibility의 핵심 channel. 2026 Apple Vision Pro·Quest 3·PSVR 2가 모두 eye tracking을 표준화하면서 architecture-level 시스템 component로 격상. ## 매 핵심 ### 매 4 가지 안구 운동 - **Saccade**: 빠른 도약 (200-300°/s), 도중에는 시각 정보 suppress (saccadic suppression). - **Smooth pursuit**: 움직이는 target 추적, 대상 없이 의식적으로 만들 수 없음. - **Fixation**: 한 점 응시 (200-300ms 평균), micro-tremor 포함. - **Vergence**: 양안의 거리 조절 — depth/3D UI에서 핵심. ### 매 architecture 역할 - **Input**: gaze + dwell, gaze + pinch (Vision Pro 모델). 정확도 ~1°. - **Foveated rendering**: gaze 주변 high-res, 주변부 low-res → GPU 50-70% 절약. - **Attention metric**: heatmap 기반 UX 검증, A/B test의 implicit signal. - **Accessibility**: ALS 등 운동 장애 사용자의 통신 channel. ### 매 응용 1. **VR/AR**: foveated rendering, 자연스러운 selection. 2. **Web analytics**: heatmap (Hotjar, Microsoft Clarity). 3. **자동차 HMI**: 운전자 attention 모니터링 (Tesla driver-facing camera, Cadillac Super Cruise). 4. **의료**: 신경학적 진단 (saccade latency = Parkinson 지표). ## 💻 패턴 ### WebXR로 gaze ray 얻기 (Vision Pro Safari) ```typescript // XRSession with eye-tracking feature const session = await navigator.xr!.requestSession('immersive-vr', { requiredFeatures: ['hand-tracking', 'eye-tracking'], }); session.requestAnimationFrame(function frame(_t, xrFrame) { const referenceSpace = /* … */; for (const source of xrFrame.session.inputSources) { if (source.targetRayMode === 'gaze') { const pose = xrFrame.getPose(source.targetRaySpace, referenceSpace); if (pose) handleGazeRay(pose.transform); } } session.requestAnimationFrame(frame); }); ``` ### Dwell-time selection ```typescript class GazeDwellSelector { private hovered: Element | null = null; private since = 0; constructor(private readonly thresholdMs = 800) {} update(target: Element | null, now: number) { if (target !== this.hovered) { this.hovered = target; this.since = now; target?.dispatchEvent(new CustomEvent('gazeenter')); return; } if (target && now - this.since >= this.thresholdMs) { target.dispatchEvent(new CustomEvent('gazeselect')); this.since = Number.POSITIVE_INFINITY; // 한 번만 fire } } } ``` ### Fixation detection (I-DT algorithm) ```typescript // I-DT: dispersion-threshold identification type Sample = { x: number; y: number; t: number }; export function detectFixations( samples: Sample[], windowMs = 100, dispersionDeg = 1.0, ): Array<{ start: number; end: number; cx: number; cy: number }> { const out: any[] = []; let i = 0; while (i < samples.length) { let j = i + 1; while (j < samples.length && samples[j].t - samples[i].t < windowMs) j++; const win = samples.slice(i, j); const xs = win.map(s => s.x), ys = win.map(s => s.y); const disp = (Math.max(...xs) - Math.min(...xs)) + (Math.max(...ys) - Math.min(...ys)); if (disp < dispersionDeg) { // extend while (j < samples.length) { const x2 = [...xs, samples[j].x], y2 = [...ys, samples[j].y]; const d = (Math.max(...x2) - Math.min(...x2)) + (Math.max(...y2) - Math.min(...y2)); if (d >= dispersionDeg) break; xs.push(samples[j].x); ys.push(samples[j].y); j++; } out.push({ start: samples[i].t, end: samples[j - 1].t, cx: avg(xs), cy: avg(ys), }); } i = j; } return out; } const avg = (xs: number[]) => xs.reduce((a, b) => a + b, 0) / xs.length; ``` ### Foveated rendering hint (WebGPU) ```typescript // 2026 WebGPU에서 variable rate shading via gaze const gaze = getGazeNDC(); // [-1,1]^2 device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([ gaze.x, gaze.y, /*innerRadius*/ 0.15, /*outerRadius*/ 0.45, ])); // fragment shader: distance(uv, gaze) > outer ⇒ discard 75% samples ``` ### Saccade 중 UI 변화 (change blindness 활용) ```typescript // saccade 검출 시 다음 frame에 layout 변경 → 사용자가 인지 못함 function onSaccadeStart(cb: () => void) { // velocity > 200 deg/s 임계 let last: Sample | null = null; return (s: Sample) => { if (last) { const v = Math.hypot(s.x - last.x, s.y - last.y) / (s.t - last.t) * 1000; if (v > 200) cb(); } last = s; }; } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | VR/AR primary input | gaze + pinch (Vision Pro 패턴) | | Desktop accessibility | dwell selection (800-1500ms) | | Analytics only | heatmap aggregation, real-time 처리 X | | 의료 진단 | 120Hz+ 정밀 tracker, raw sample 저장 | **기본값**: 정확도 1° / 60Hz / dwell 800ms — 일반 UX의 baseline. ## 🔗 Graph - 부모: [[Human-Computer Interaction]] · [[Input Modalities]] - 변형: [[Eye Tracking]] · [[Gaze-based Interaction]] - 응용: [[Foveated Rendering]] · [[Accessibility]] · [[VR UX]] - Adjacent: [[Attention Modeling]] · [[Vision Pro Architecture]] · [[WebXR]] ## 🤖 LLM 활용 **언제**: VR/AR 입력 설계, gaze heatmap 분석 결과 해석. **언제 X**: gaze data 정확도가 낮은 환경 (일반 webcam 기반 1° 이상 오차)에서 critical input으로 사용 — false trigger 폭주. ## ❌ 안티패턴 - **Midas touch**: 보는 것을 모두 click으로 해석 → 의도하지 않은 trigger. dwell·confirmation 필수. - **고정 dwell time**: 사용자별 적응 필요 — 노약자는 길게. - **Saccade 중 UI 깜빡임**: 사용자에 멀미·혼란. - **Calibration 없이 시작**: 정확도 5° 이상 → 사실상 무용. ## 🧪 검증 / 중복 - Verified (Apple visionOS HIG 2026; Tobii eye-tracking research; Salvucci & Goldberg I-DT 2000). - 신뢰도 B (HCI 분야 표준이지만 architecture wiki에서는 보조 주제). ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — saccade/fixation/vergence·WebXR·I-DT 알고리즘 |