В этом руководстве показано, как использовать Cardboard SDK для Android для создания собственных приложений виртуальной реальности (VR).
С помощью Cardboard SDK вы можете превратить смартфон в платформу виртуальной реальности. Смартфон может отображать 3D-сцены со стереоскопическим рендерингом, отслеживать и реагировать на движения головы, а также взаимодействовать с приложениями, определяя нажатие пользователем кнопки просмотра.
Для начала вам понадобится HelloCardboard — демо-игра, демонстрирующая основные функции Cardboard SDK. В игре пользователи исследуют виртуальный мир, находят и собирают предметы. В ней показано, как:
- Настройте среду разработки
- Загрузите и создайте демо-приложение
- Отсканируйте QR-код устройства просмотра Cardboard, чтобы сохранить его параметры.
- Отслеживайте движения головы пользователя
- Визуализация стереоскопических изображений путем установки правильной матрицы проекции для каждого глаза
HelloCardboard использует Android NDK. Каждый нативный метод:
- Ограничено исключительно методом класса
HelloCardboardApp
или - Создает или удаляет экземпляр этого класса
Настройте среду разработки
Требования к оборудованию:
- Устройство Android под управлением Android 8.0 «Oreo» (уровень API 26) или выше
- Картонный просмотрщик
Требования к программному обеспечению:
- Android Studio версии 2024.1.2 «Koala Feature Drop» или выше
- Android SDK 15.0 «Vanilla Ice Cream» (уровень API 35) или выше
Последняя версия фреймворка Android NDK
Чтобы просмотреть или обновить установленные SDK, перейдите в «Настройки» > «Внешний вид и поведение».
Системные настройки > Android SDK в Android Studio.
Загрузите и создайте демо-приложение
Cardboard SDK собран с использованием предварительно скомпилированного заголовочного файла Vulkan для каждого шейдера. Инструкции по созданию заголовочных файлов с нуля можно найти здесь .
Выполните следующую команду, чтобы клонировать Cardboard SDK и демонстрационное приложение HelloCardboard из GitHub:
git clone https://github.com/googlevr/cardboard.git
В Android Studio выберите «Открыть существующий проект Android Studio» , затем выберите каталог, в который были клонированы Cardboard SDK и демонстрационное приложение HelloCardboard.
Ваш код появится в окне проекта в Android Studio.
Чтобы собрать Cardboard SDK, дважды щелкните параметр сборки в папке cartboard/:sdk/Tasks/build на вкладке Gradle (Вид > Окна инструментов > Gradle).
Запустите демонстрационное приложение HelloCardboard на своем телефоне, выбрав «Запустить» > «Запустить...» , и выберите целевой объект
hellocardboard-android
.
Отсканируйте QR-код
Чтобы сохранить параметры устройства, отсканируйте QR-код на устройстве просмотра Cardboard:
Если пользователь нажимает кнопку «ПРОПУСТИТЬ» и ранее сохраненных параметров нет, Cardboard сохраняет параметры Google Cardboard v1 (представленного на Google I/O 2014).
Попробуйте демо-версию
В HelloCardboard вы будете искать и собирать геодезические сферы в трехмерном пространстве.
Чтобы найти и собрать сферу:
Поворачивайте голову в любом направлении, пока не увидите плавающую фигуру.
Посмотрите прямо на сферу. Это заставит её менять цвет.
Нажмите кнопку просмотра Cardboard, чтобы «собрать» сферу.
Настройте устройство
Когда пользователь нажимает на значок шестеренки для переключения между устройствами Cardboard, вызывается метод nativeSwitchViewer
. nativeSwitchViewer
вызывает CardboardQrCode_scanQrCodeAndSaveDeviceParams
, который открывает окно для сканирования QR-кода устройства Cardboard. Диспропорция объектива устройства Cardboard и другие параметры обновляются после сканирования QR-кода.
// Called by JNI method
void HelloCardboardApp::SwitchViewer() {
CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}
Включить эмулятор Android Studio x86
Для сборки для эмулятора Android Studio x86 удалите следующую строку из файлов build.gradle
в SDK и Sample :
abiFilters 'armeabi-v7a', 'arm64-v8a'
Это активирует все ABI и значительно увеличит размер создаваемого .aar
файла. Подробнее см. в разделе Android ABI .
Отслеживание положения головы
Создать хед-трекер
Трекер движения головы создается один раз в конструкторе HelloCardboardApp
:
HelloCardboardApp::HelloCardboardApp(JavaVM* vm, jobject obj, jobject asset_mgr_obj) {
Cardboard_initializeAndroid(vm, obj); // Must be called in constructor
head_tracker_ = CardboardHeadTracker_create();
}
При создании VrActivity
экземпляр класса HelloCardboardApp
генерируется путем вызова метода nativeOnCreate
:
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
nativeApp = nativeOnCreate(getAssets());
//...
}
Приостановка и возобновление отслеживания движения головы
Для приостановки, возобновления и уничтожения устройства отслеживания движения головы необходимо вызвать CardboardHeadTracker_pause(head_tracker_)
, CardboardHeadTracker_resume(head_tracker_)
и CardboardHeadTracker_destroy(head_tracker_)
соответственно. В приложении HelloCardboard мы вызываем их в nativeOnPause
, nativeOnResume
и nativeOnDestroy
:
// Code to pause head tracker in hello_cardboard_app.cc
void HelloCardboardApp::OnPause() { CardboardHeadTracker_pause(head_tracker_); }
// Call nativeOnPause in VrActivity
@Override
protected void onPause() {
super.onPause();
nativeOnPause(nativeApp);
//...
}
// Code to resume head tracker in hello_cardboard_app.cc
void HelloCardboardApp::onResume() {
CardboardHeadTracker_resume(head_tracker_);
//...
}
// Call nativeOnResume in VrActivity
@Override
protected void onResume() {
super.onResume();
//...
nativeOnResume(nativeApp);
}
// Code to destroy head tracker in hello_cardboard_app.cc
HelloCardboardApp::~HelloCardboardApp() {
CardboardHeadTracker_destroy(head_tracker_);
//...
}
// Call nativeOnDestroy in VrActivity
@Override
protected void onDestroy() {
super.onDestroy();
nativeOnDestroy(nativeApp);
nativeApp = 0;
}
Искажение объектива
Каждый раз, когда Cardboard сканирует новый QR-код, следующий код считывает сохраненные параметры и использует их для создания объекта искажения объектива, который применяет правильное искажение объектива к отображаемому контенту:
CardboardQrCode_getSavedDeviceParams(&buffer, &size);
CardboardLensDistortion_destroy(lens_distortion_);
lens_distortion_ = CardboardLensDistortion_create(
buffer, size, screen_width_, screen_height_);
CardboardQrCode_destroy(buffer);
Рендеринг
Рендеринг контента в Cardboard включает в себя следующее:
- Создание текстур
- Получение матриц вида и проекции для левого и правого глаза
- Создание рендерера и настройка сетки искажения
- Рендеринг каждого кадра
Создание текстур
Весь контент отрисовывается на текстуре, которая разделена на секции для левого и правого глаза. Эти секции инициализируются в _leftEyeTexture
и _rightEyeTexture
соответственно.
void HelloCardboardApp::GlSetup() {
LOGD("GL SETUP");
if (framebuffer_ != 0) {
GlTeardown();
}
// Create render texture.
glGenTextures(1, &texture_);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screen_width_, screen_height_, 0,
GL_RGB, GL_UNSIGNED_BYTE, 0);
left_eye_texture_description_.texture = texture_;
left_eye_texture_description_.left_u = 0;
left_eye_texture_description_.right_u = 0.5;
left_eye_texture_description_.top_v = 1;
left_eye_texture_description_.bottom_v = 0;
right_eye_texture_description_.texture = texture_;
right_eye_texture_description_.left_u = 0.5;
right_eye_texture_description_.right_u = 1;
right_eye_texture_description_.top_v = 1;
right_eye_texture_description_.bottom_v = 0;
//...
CHECKGLERROR("GlSetup");
}
Эти текстуры передаются в качестве параметров в CardboardDistortionRenderer_renderEyeToDisplay
.
Получить матрицы вида и проекции для левого и правого глаза
Сначала получим матрицы для левого и правого глаза:
CardboardLensDistortion_getEyeFromHeadMatrix(
lens_distortion_, kLeft, eye_matrices_[0]);
CardboardLensDistortion_getEyeFromHeadMatrix(
lens_distortion_, kRight, eye_matrices_[1]);
CardboardLensDistortion_getProjectionMatrix(
lens_distortion_, kLeft, kZNear, kZFar, projection_matrices_[0]);
CardboardLensDistortion_getProjectionMatrix(
lens_distortion_, kRight, kZNear, kZFar, projection_matrices_[1]);
Затем получите сетки искажений для каждого глаза и передайте их в рендерер искажений:
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kLeft, &left_mesh);
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kRight, &right_mesh);
Создайте рендерер и установите правильную сетку искажения.
Рендерер необходимо инициализировать только один раз. После создания рендерера установите новую сетку искажения для левого и правого глаза в соответствии со значениями сетки, возвращаемыми функцией CardboardLensDistortion_getDistortionMesh
.
distortion_renderer_ = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(distortion_renderer_, &left_mesh, kLeft);
CardboardDistortionRenderer_setMesh(distortion_renderer_, &right_mesh, kRight);
Рендеринг контента
Для каждого кадра извлеките текущую ориентацию головы из CardboardHeadTracker_getPose
:
CardboardHeadTracker_getPose(head_tracker_, monotonic_time_nano, &out_position[0], &out_orientation[0]);
Используйте текущую ориентацию головы с матрицами вида и проекции, чтобы составить матрицу проекции вида для каждого из глаз и вывести содержимое на экран:
// Draw eyes views
for (int eye = 0; eye < 2; ++eye) {
glViewport(eye == kLeft ? 0 : screen_width_ / 2, 0, screen_width_ / 2,
screen_height_);
Matrix4x4 eye_matrix = GetMatrixFromGlArray(eye_matrices_[eye]);
Matrix4x4 eye_view = eye_matrix * head_view_;
Matrix4x4 projection_matrix =
GetMatrixFromGlArray(projection_matrices_[eye]);
Matrix4x4 modelview_target = eye_view * model_target_;
modelview_projection_target_ = projection_matrix * modelview_target;
modelview_projection_room_ = projection_matrix * eye_view;
// Draw room and target. Replace this to render your own content.
DrawWorld();
}
Используйте CardboardDistortionRenderer_renderEyeToDisplay
, чтобы применить коррекцию искажения к содержимому и вывести содержимое на экран.
// Render
CardboardDistortionRenderer_renderEyeToDisplay(
distortion_renderer_, /* target_display = */ 0, /* x = */ 0, /* y = */ 0,
screen_width_, screen_height_, &left_eye_texture_description_,
&right_eye_texture_description_);