Разработка gaze-интерфейса для мобильного VR: raycast, dwell, reticle

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Разработка gaze-интерфейса для мобильного VR: raycast, dwell, reticle
Средний
~3-5 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    744
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    562

Мобильный VR без контроллеров — единственный способ взаимодействия — направление взгляда. Кажется, просто смотри на кнопку — она нажимается. На практике неправильно реализованный gaze раздражает пользователя быстрее любого другого UI-паттерна. За годы работы мы выработали стек и подходы, гарантирующие комфортное взаимодействие. Наш опыт — 5+ лет в мобильной VR-разработке, более 20 проектов с gaze-интерфейсом. Мы предлагаем готовое решение под ключ: от raycast до прогресс-индикатора. Базовую систему реализуем за 3–5 дней, полную — за 1–2 недели. Согласно Google Cardboard документации, gaze-based interaction является стандартным методом ввода для мобильного VR без контроллеров.

Как работает raycast из центра взгляда?

Gaze определяется направлением взгляда камеры. Ray пускается из позиции камеры вперёд по Camera.main.transform.forward:

void FixedUpdate() {
    Ray gazeRay = new Ray(Camera.main.transform.position,
                          Camera.main.transform.forward);

    if (Physics.Raycast(gazeRay, out RaycastHit hit, maxGazeDistance, interactableLayer)) {
        var target = hit.collider.GetComponent<IGazeTarget>();
        if (target != null) {
            HandleGazeHit(target, hit.point);
        } else {
            HandleGazeMiss();
        }
    } else {
        HandleGazeMiss();
    }
}

FixedUpdate() вместо Update() — стабильная частота вызовов не привязана к FPS. На слабых устройствах при просадках до 30 FPS Update() даёт неравномерный отклик. Слой interactableLayer — обязательно: raycast по всей сцене дорого, и пользователь не должен случайно активировать невидимые коллайдеры.

Как реализовать reticle (курсор взгляда)?

Reticle — визуальный индикатор точки взгляда. Размещается в world space на поверхности объекта под взглядом. Расстояние динамическое: reticle «прилипает» к хитпойнту.

void UpdateReticle(Vector3 hitPoint, Vector3 hitNormal) {
    reticleTransform.position = hitPoint + hitNormal * RETICLE_OFFSET;
    reticleTransform.rotation = Quaternion.LookRotation(-hitNormal);

    // Масштаб постоянный в угловых единицах (constant apparent size)
    float dist = Vector3.Distance(Camera.main.transform.position, hitPoint);
    reticleTransform.localScale = Vector3.one * dist * ANGULAR_SIZE;
}

Отметим: когда объекта под взглядом нет — reticle на дефолтном расстоянии (3–5 метров). Не прячем его: пользователь всегда должен видеть, куда смотрит.

Dwell-активация и прогресс-индикатор

Пользователь смотрит на объект N секунд — происходит активация. Оптимальное время dwell: 1.2–2.0 секунды. Меньше 1 секунды — случайные активации при обзоре сцены, больше 2 секунд — утомляет. Прогресс должен быть заметен. Заполняющееся кольцо вокруг reticle — стандарт:

public class GazeDwellController : MonoBehaviour {
    [SerializeField] private float dwellTime = 1.5f;
    [SerializeField] private Image progressRing;

    private float dwellProgress = 0f;
    private IGazeTarget currentTarget;
    private bool isActivated = false;

    public void OnGazeEnter(IGazeTarget target) {
        currentTarget = target;
        dwellProgress = 0f;
        isActivated = false;
        progressRing.gameObject.SetActive(true);
    }

    public void OnGazeStay() {
        if (isActivated) return;
        dwellProgress += Time.deltaTime / dwellTime;
        progressRing.fillAmount = dwellProgress;

        if (dwellProgress >= 1f) {
            isActivated = true;
            currentTarget?.OnGazeActivate();
            StartCoroutine(ResetAfterDelay(0.5f));
        }
    }

    public void OnGazeExit() {
        currentTarget = null;
        progressRing.gameObject.SetActive(false);
        dwellProgress = 0f;
    }
}

После активации — короткий cooldown перед следующей активацией того же объекта (0.5–1.0 сек). Иначе пользователь не успевает убрать взгляд и кнопка «нажимается» дважды.

Hover-состояние: обратная связь до активации

Отметим: когда пользователь смотрит на объект, но dwell ещё не завершён, нужна немедленная визуальная обратная связь. Объект должен как-то отреагировать при OnGazeEnter — до истечения времени активации. Варианты:

  • Подсветка: изменение emission цвета материала
  • Масштаб: объект слегка увеличивается (0.05f хватает)
  • Анимация: иконка реагирует на взгляд
  • Звуковой сигнал: короткий click при начале dwell

Без этого пользователь не понимает, «видит» ли его приложение.

Cardboard button как подтверждение

У Cardboard есть физическая кнопка (магнитный триггер). Добавляем её как альтернативный метод активации вместо dwell — для продвинутых пользователей это быстрее и удобнее:

// Cardboard SDK trigger event
void Update() {
    if (CardboardInput.GetButtonDown()) {
        TriggerCurrentGazeTarget();
    }
}

Кнопка — не замена dwell, а дополнение. Не все корпусы Cardboard имеют рабочую магнитную кнопку.

Какие типичные ошибки возникают при gaze-взаимодействии?

Слишком маленький коллайдер у интерактивного объекта — пользователь «промахивается» мимо кнопки. Коллайдер должен быть на 10–20% больше видимого объекта. Скорость взгляда (угловая скорость) влияет на точность: при быстром обзоре порог скорости сбрасывает dwell. Reticle дрожит из-за гироскопа — Lerp с временем 20 мс устраняет дрожание. Используйте отдельный слой для raycast, чтобы избежать случайных активаций и сэкономить производительность.

Ошибка Решение
Слишком маленький коллайдер Увеличить коллайдер на 10–20% относительно визуала
Случайные активации Порог угловой скорости головы при старте dwell
Дрожание reticle Lerp позиции reticle с time ~20ms

Сравнение методов активации

Параметр Dwell-активация Cardboard кнопка
Готовность на всех устройствах Да Нет (не у всех работает)
Утомляемость Средняя Низкая
Точность Хорошая Высокая
Настройка времени Да (1.2–2.0 с) Нет

Что входит в работу

  • Документация архитектуры gaze-системы
  • Исходный код: raycast, reticle, dwell controller, hover-состояние
  • Интеграция с Cardboard SDK и альтернативными триггерами
  • Тестирование на устройствах (iOS/Android) с разными версиями Cardboard
  • Поддержка 2 недели после сдачи

Процесс работы

  1. Анализ интерактивных элементов: типы объектов, сценарии взаимодействия.
  2. Реализация raycast-системы с правильными слоями и коллайдерами.
  3. Reticle в world space с constant apparent size.
  4. Dwell controller с прогресс-индикатором, hover-состоянием, cooldown.
  5. Cardboard button как альтернативный триггер.
  6. Тестирование комфорта: время dwell, размеры кнопок, обратная связь.

Ориентиры по срокам

Базовая gaze interaction система с reticle и dwell — 3–5 дней. Полноценная система с несколькими типами интерактивных объектов, анимациями, звуком и настраиваемыми параметрами — 1–2 недели.

Гарантируем комфортное взаимодействие. Сертифицированные разработчики Unity и Android/iOS. Свяжитесь с нами, чтобы обсудить ваш проект — реализуем gaze-интерфейс для вашего мобильного VR-приложения.

Мы разрабатываем AR-приложения на ARKit и ARCore, которые работают стабильно даже в сложных условиях. Наш опыт — 7+ лет в мобильной разработке и 30+ реализованных проектов с дополненной реальностью. Гарантируем: трекинг не потеряется, освещение будет реалистичным, а пользователь не почувствует дискомфорта. Сертифицированные разработчики Apple и Google.

Почему трекинг теряется и как это исправить?

ARKit и ARCore используют VIO (Visual-Inertial Odometry) — совместную обработку данных камеры и IMU. Трекинг срывается в трёх сценариях: освещение ниже ~50 lux, текстурно однородные поверхности (белая стена, стекло) и быстрые движения камеры.

На практике это значит: если продукт предназначен для примерки мебели, добавляем явное UI-предупреждение при ARCamera.TrackingState.limited(.insufficientFeatures). Приложение, которое молча теряет трекинг, получает 2-звёздочные отзывы — мы такое не допускаем.

Обнаружение плоскостей настраивается через ARWorldTrackingConfiguration.planeDetection = [.horizontal, .vertical]. Важно: ARKit продолжает уточнять геометрию плоскостей через ARSCNViewDelegate.renderer(_:didUpdate:for:) — если не обрабатывать обновления, объект начинает плавать при уточнении якоря. Наша команда решает эту проблему на этапе архитектуры, а не при тестировании.

AR Foundation: кросс-платформа с нюансами

Unity AR Foundation — слой абстракции поверх ARKit и ARCore. Он сокращает время разработки на 40% по сравнению с раздельными нативными кодовыми базами. Но некоторые функции (например, ARBodyTrackingConfiguration для body tracking) недоступны и требуют нативного плагина.

Для React Native и Flutter прямой AR Foundation отсутствует. Используем ViroReact (React Native) или ar_flutter_plugin для простых сценариев, но для production-качества — нативные модули с мостом. Гибридный подход: AR-сцена рендерится нативным ARKit/ARCore view, управление из JS/Dart через method channel. Входит в нашу стандартную поставку.

Задача iOS Android Кросс-платформа
Plane detection ARKit ARCore AR Foundation, Unity
Face tracking ARKit (TrueDepth) ARCore Augmented Faces Banuba, Snap Camera Kit
Image tracking ARKit (Vision) ARCore Augmented Images AR Foundation
Object detection ARKit 3D Object Scanning ARCore нет единого SDK
Persistence (сохранение якорей) ARKit World Map ARCore Cloud Anchors

Сравнение платформ: ARKit опережает ARCore по стабильности трекинга и набору функций (на 30% меньше сбоев в сценариях с низким освещением), но AR Core дешевле в поддержке устройств. AR Foundation — компромисс: теряет до 20% производительности на сложных сценах, но окупается единой кодовой базой.

Try-on: примерка товаров через AR

Примерка очков, украшений, косметики — отдельный класс задач. Здесь нужен face tracking, а не plane detection.

ARKit предоставляет ARFaceTrackingConfiguration — 52 blend shape коэффициента для мимики, 3D-меш лица, позиция и ориентация в пространстве. Работает только на устройствах с TrueDepth-камерой (iPhone с Face ID).

Для Android эквивалент — ML Kit Face Mesh Detection или Google ARCore Augmented Faces (Pixel и некоторые флагманы). Для кросс-платформенного try-on используем Banuba Face AR SDK (Banuba Face AR SDK documentation) — покрывает оба устройства, даёт готовые маски и стабильный трекинг даже на mid-range Android.

Качество try-on критически зависит от 3D-моделей товаров. Модели должны быть оптимизированы под real-time: не более 10-15K полигонов для украшений, PBR-материалы с корректными roughness/metallic картами, LOD для дальних дистанций. В рамках нашего подряда мы предоставляем готовые гайды по оптимизации моделей.

Как добиться реалистичного освещения в AR?

ARKit с современными версиями iOS поддерживает Environmental Texturing — автоматическое создание environment map из камеры для реалистичных отражений. Включается через ARWorldTrackingConfiguration.environmentTexturing = .automatic. Без этого металлические и стеклянные материалы выглядят пластиково.

ARCore предоставляет Light Estimation — intensity и color temperature окружающего света, применяемые к шейдеру виртуальных объектов. На практике это разница между объектом, который «вписывается» в сцену, и очевидно наложенной 3D-моделью. Мы гарантируем, что финальное изображение не выдаёт виртуальности.

Что входит в работу

  • Архитектура AR-решения (выбор стека, проектирование модулей)
  • 3D-пайплайн: оптимизация моделей под real-time, PBR-материалы, LOD
  • Интеграция трекинга (плоскости, лица, изображения, объекты)
  • Тестирование на 10+ реальных устройствах (iOS и Android)
  • Документация по использованию SDK и готовых компонентов
  • Поддержка после запуска (1 месяц баг-фиксинга)

Сроки и оценка

Простая AR-сцена с размещением одной 3D-модели на плоскости — 1–2 недели. Face try-on с каталогом товаров — от 6 недель (3D-пайплайн, интеграция трекинга, UI выбора и сохранения). Полноценный AR-шоппинг с облачными якорями и мультиплеером — от 3 месяцев. Оценим проект за 1 день — пишите, обсудим вашу AR-идею.