В этом руководстве показано, как использовать Cardboard SDK для Android для создания собственных возможностей виртуальной реальности (VR).
Вы можете использовать Cardboard SDK, чтобы превратить смартфон в платформу VR. Смартфон может отображать 3D-сцены со стереоскопическим рендерингом, отслеживать движения головы и реагировать на них, а также взаимодействовать с приложениями, определяя, когда пользователь нажимает кнопку просмотра.
Для начала вы воспользуетесь HelloCardboard — демонстрационной игрой, демонстрирующей основные функции Cardboard SDK. В игре пользователи осматривают виртуальный мир, находя и собирая объекты. Он покажет вам, как:
- Настройте среду разработки
- Загрузите и создайте демо-приложение
- Отсканируйте QR-код просмотрщика Cardboard, чтобы сохранить его параметры.
- Отслеживайте движения головы пользователя
- Рендеринг стереоскопических изображений, установив правильную матрицу проекции вида для каждого глаза.
HelloCardboard использует Android NDK. Каждый нативный метод:
- Уникально привязан к методу класса
HelloCardboardApp
или - Создает или удаляет экземпляр этого класса
Настройте среду разработки
Требования к оборудованию:
- Устройство Android под управлением Android 8.0 «Oreo» (уровень API 26) или более поздней версии.
- Картонный просмотрщик
Требования к программному обеспечению:
- Android Studio версии 2022.1.1 «Электрический угорь» или выше
- Android SDK 13.0 «Тирамису» (уровень API 33) или выше
Последняя версия платформы 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, дважды щелкните параметр сборки в папке cardboard/:sdk/Tasks/build на вкладке Gradle («Просмотр» > «Инструменты Windows» > Gradle).
Запустите демонстрационное приложение HelloCardboard на своем телефоне, выбрав «Выполнить» > «Выполнить...» и выберите цель
hellocardboard-android
.
Сканируйте QR-код
Чтобы сохранить параметры устройства, отсканируйте QR-код во просмотрщике Cardboard:
Если пользователь нажимает «Пропустить» и ранее сохраненных параметров нет, Cardboard сохраняет параметры Google Cardboard v1 (запущен на Google I/O 2014).
Попробуйте демо
В HelloCardboard вы будете искать и собирать геодезические сферы в трехмерном пространстве.
Чтобы найти и собрать сферу:
Поверните голову в любом направлении, пока не увидите плавающую фигуру.
Посмотрите прямо на сферу. Это приводит к изменению цвета.
Нажмите кнопку просмотра картона, чтобы «собрать» сферу.
Настройка устройства
Когда пользователь нажимает значок шестеренки для переключения средств просмотра Cardboard, вызывается метод nativeSwitchViewer
. nativeSwitchViewer
вызывает CardboardQrCode_scanQrCodeAndSaveDeviceParams
, который открывает окно для сканирования QR-кода средства просмотра. Искажение объектива зрителя и другие параметры обновляются после сканирования 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_);