Google Cardboard — самый демократичный способ попасть в VR: картонный корпус за несколько долларов, смартфон внутри. Для разработчика это значит: стереоскопический рендеринг, трекинг головы через IMU, и жёсткие ограничения по производительности — всё это делается на обычном мобильном железе без специализированного VR-процессора. Мы разрабатываем VR-приложения под Cardboard на iOS и Android с использованием Swift и Kotlin. Опыт нашей команды — 5 лет в мобильной VR-разработке, более 20 проектов. Ниже разберём ключевые технические задачи и их решения.
Как избежать motion sickness в Google Cardboard?
Motion sickness возникает, когда visual latency > 20ms. IMU работает на 200–1000Hz, но рендеринг на 60Hz. Для компенсации используется ATW (Asynchronous TimeWarp) — перепроецирование последнего кадра с учётом новой ориентации головы за время между рендером и выводом на экран. В Cardboard SDK ATW реализован автоматически. Убедитесь, что Cardboard.SDK.UpdateScreenParams() вызывается в начале каждого Update(), а не реже.
Рекомендации по Scene Design для снижения укачивания:
- Нет acceleration-based locomotion (телепортация предпочтительнее)
- Постоянный горизонт или cockpit-reference (кабина, интерьер) снижают дискомфорт
- Не масштабируйте мир относительно игрока в рантайме
Стереоскопический рендеринг: split-screen
Экран делится пополам. Левая половина — для левого глаза, правая — для правого. Каждая половина рендерится с небольшим смещением камеры (IPD — interpupillary distance, ~63–65mm). Разница между двумя изображениями создаёт стереоэффект.
В Unity это управляется через CardboardCamera компонент с двумя рендер-текстурами. Каждая текстура рендерится отдельно, затем применяется barrel distortion correction.
Критичная проблема производительности: two-pass rendering удваивает нагрузку на GPU. На среднем смартфоне при 1080p это 30–40 FPS без оптимизаций. Решения:
- Foveated rendering — снижение разрешения по краям экрана (не центральная область видна через линзы)
- Single Pass Instanced Rendering в Unity (рендеринг обоих глаз за один draw call). Этот метод в 2 раза быстрее two-pass.
- Снижение разрешения рендер-текстур до 0.7–0.8 от экранного разрешения
| Метод | FPS (1080p, средний смартфон) | Качество изображения |
|---|---|---|
| Two-pass | 30–40 | Полное разрешение |
| Single Pass Instanced | 55–60 | Полное разрешение |
| Foveated + Single Pass | 60+ | Снижено по краям |
Head tracking и интеграция SDK
После того как Google открыл исходники Cardboard SDK, он стал официальным путём для Cardboard-приложений на iOS и Android. SDK предоставляет:
- Дисторция-коррекцию для линз (каждый корпус имеет свой lens distortion profile, сканируемый QR-кодом)
- Head tracking через фьюжн данных акселерометра и гироскопа (IMU fusion)
- Eye matrices для корректной проекции на каждый глаз
- Trigger button обработку (магнитная кнопка в картонном Cardboard)
Unity интеграция — com.google.cardboard UPM пакет. После подключения:
void Update() {
Cardboard.SDK.UpdateScreenParams();
// Позиция/ротация головы применяется автоматически через CardboardCamera компонент
}
Нативная Android интеграция через CardboardHeadTracker и CardboardLensDistortion:
headTracker = CardboardHeadTracker.create();
lensDistortion = CardboardLensDistortion.create(encodedDeviceParams, width, height);
headTracker.getPose(monotonic_time_nanos, target_time_nanos, outEyeFromHead);
Ввод: кнопка и Gaze
У базового Cardboard одна кнопка. Всё взаимодействие строится на:
- Gaze input — курсор следует за взглядом, активация по фиксации взгляда (dwell time, обычно 1.5–2 сек)
- Trigger button — подтверждение выбора, телепортация
Gaze reticle рендерится в world space на фиксированном расстоянии от камеры. Raycast из центра каждого глаза определяет объект под курсором:
void Update() {
Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
if (Physics.Raycast(ray, out RaycastHit hit, maxDistance, interactableLayer)) {
gazeTarget = hit.collider.GetComponent<IGazeable>();
gazeTarget?.OnGazeEnter();
gazeTimer += Time.deltaTime;
if (gazeTimer >= DWELL_TIME) {
gazeTarget?.OnGazeActivate();
gazeTimer = 0f;
}
} else {
gazeTarget?.OnGazeExit();
gazeTimer = 0f;
}
}
QR-сканирование профиля устройства
При первом запуске пользователь сканирует QR-код с корпуса Cardboard. SDK загружает lens distortion profile для конкретного корпуса. Без этого шага искажение некорректно — изображение выглядит деформированным. Cardboard SDK сохраняет профиль в SharedPreferences / NSUserDefaults после сканирования. Добавьте на первый экран инструкцию с иконкой QR и явную кнопку «повторно отсканировать устройство» в настройках.
Что входит в работу
- Исходный код приложения с комментариями
- Документирование API и ключевых компонентов
- Инструкция по QR-сканированию для пользователей
- Поддержка при публикации в App Store и Google Play
- Тестирование на 5+ устройствах разных ценовых сегментов
Процесс работы
- Анализ: определение типа приложения (пассивный опыт или интерактивный), целевой аудитории и требований к производительности.
- Настройка Cardboard SDK: подключение Unity пакета или нативная интеграция, конфигурация проекции.
- Разработка сцены: моделирование с учётом VR-ограничений, реализация gaze input.
- Оптимизация: Single Pass Instanced, foveated rendering, LOD, тестирование FPS.
- Тестирование на устройствах разных ценовых сегментов, оценка комфорта.
- Деплой: подготовка билдов, загрузка в App Store Connect и Google Play Console.
Ориентиры по срокам
Простой пассивный VR-опыт (360-контент, базовая навигация взглядом) — 1–2 недели. Интерактивное VR-приложение с игровой механикой, множеством сцен и полным UI — 2–3 месяца.
Оцените ваш проект: свяжитесь с нами для предварительного расчёта сроков и стоимости. Закажите разработку мобильного VR-приложения под Google Cardboard — получите консультацию инженера с 5-летним опытом.







