Building a Dichoptic Vision-Training Game in Unity for Meta Quest: Lessons from AmblyoPunch
The August 2026 VR Games Showcase just dropped (Road to VR has the full rundown). While the headlines chase Total Chaos VR and the latest ports, I want to zoom in on a different launch: AmblyoPunch — a Meta Quest title that delivers dichoptic amblyopia therapy through an arcade loop.
Tech stack: Unity + URP + Meta XR SDK. Target: Quest 2/3/Pro. Single APK, no backend.
The core challenge: rendering two different images — one per eye — in real time, at 72/90Hz, with precise control over spatial frequency, contrast, and luminance of Gabor-pattern stimuli.
How we solved it:
-
Single-pass stereo with custom shader
- Unity’s single-pass instanced rendering gives us
unity_StereoEyeIndexin the vertex shader. - We branch per-eye in a fragment shader that procedurally generates Gabor patches (sinusoid × Gaussian envelope) on the GPU. No texture lookups, no memory bandwidth — pure math. Parameters (frequency, orientation, phase, contrast) come from a ScriptableObject progression table keyed by stage.
- Unity’s single-pass instanced rendering gives us
-
Dichoptic coin system
- Each “coin” is a quad with the Gabor shader. Left eye sees one spatial frequency; right eye sees another (or same frequency, different contrast). The brain must fuse to perceive the coin cleanly.
- Collection triggers a compute-shader-driven particle burst — also dichoptic — so reward feedback stays binocular.
-
Red-spike avoidance
- Spikes render identically to both eyes (non-dichoptic) to preserve depth cues and motion parallax. This keeps the vestibular load honest — players dodge in 6DoF, not 2D.
-
Four-stage protocol as data, not code
- Stage 1: Monocular stimulation (strong eye suppressed via alpha = 0 in shader)
- Stage 2: Binocular fusion (balanced contrast)
- Stage 3: Stereopsis recovery (disparity introduced via vertex offset)
- Stage 4: Maintenance (randomized parameters)
- All driven by a
TherapyPlanScriptableObject. Clinicians can swap plans without rebuild.
-
Performance budget
- Gabor shader: ~12 ALU instructions, zero texture fetches.
- 60+ coins on screen @ 90Hz on Quest 2: <2ms GPU.
- Zero allocations in gameplay loop — object pooling for coins, spikes, particles.
-
Calibration & safety
- First-run IPD + interpupillary distance check via
OVRPlugin.GetEyeGazesState. - Luminance calibration gray-card step (uses Quest’s factory calibration).
- Session timer + forced breaks (configurable per plan).
- First-run IPD + interpupillary distance check via
Why this matters for devs
- Medical XR doesn’t need a custom engine. Unity + URP + shader gymnastics gets you there.
- Procedural stimuli > texture atlases for vision science — infinite parameter space, zero download size.
- Single-pass stereo + per-eye shader branching is the pattern. Learn it once, reuse for any dichoptic protocol.
Open questions we’re exploring
- Dynamic contrast staircase (QUEST algorithm) driven by player performance in real time.
- Hand-tracking fallback for controller-free home use.
- Exporting session logs (CSV) for clinician review — currently local-only, looking at FHIR alignment.
Repo is private (clinical IP), but happy to field technical questions in comments.
Store link (Meta Quest): https://www.meta.com/en-gb/experiences/amblyopunch/1239507485902689/
Top comments (0)