本指南介绍了如何使用 Cardboard SDK 让 Android 打造您自己的虚拟现实 (VR) 体验。
您可以使用 Cardboard SDK 将智能手机转变为 VR 平台。智能手机 可以显示具有立体渲染效果的 3D 场景,跟踪头部动作并做出反应, 以及通过检测用户何时按下观看器按钮来与应用互动。
首先,您将使用 HelloCardboard,这是一款演示游戏,演示了 Cardboard SDK 的各项功能。在游戏中,用户环顾虚拟世界寻找和 收集对象。该指南将介绍如何执行以下操作:
- 设置您的开发环境
- 下载并构建演示版应用
- 扫描 Cardboard 观看器的二维码以保存其参数
- 跟踪用户头部的移动
- 通过为每只眼睛设置正确的视图投影矩阵,渲染立体图像
HelloCardboard 使用 Android NDK。每种原生方法都具有以下特点:
- 唯一限定于某个
HelloCardboardApp
类方法,或 - 创建或删除该类的实例
设置您的开发环境
硬件要求:
- 搭载 Android 8.0“Oreo”的 Android 设备(API 级别 26)或更高版本
- Cardboard 眼镜
软件要求:
- Android Studio 版本 2022.1.1“Electric Eel”或更高版本
- Android SDK 13.0“提拉米苏”(API 级别 33)或更高版本
最新版本的 Android NDK 框架
如需查看或更新已安装的 SDK,请前往偏好设置 >外观和行为
系统设置 >Android Studio 中的 Android SDK。
下载并构建演示版应用
Cardboard SDK 是使用预编译的 Vulkan 构建的 每个着色器的头文件。如需从头开始构建头文件的步骤,请参阅 此处。
运行以下命令以克隆 Cardboard SDK 和 HelloCardboard 演示版 应用:
git clone https://github.com/googlevr/cardboard.git
在 Android Studio 中,选择 Open an existing Android Studio Project,然后选择 目录中。
您的代码将显示在 Android Studio 的“Project”窗口中。
要组装 Cardboard SDK,请双击内的组装选项 cardboard/:sdk/Tasks/build 文件夹(位于“Gradle”标签页中,依次选择“View”>“Tool Windows”>“Gradle”)。
依次选择 Run > 在手机上运行 HelloCardboard 演示应用Run...,然后 选择
hellocardboard-android
目标
扫描二维码
要保存设备参数,请扫描 Cardboard 观看器上的二维码:
如果用户按“跳过”并且之前没有保存任何参数 Google Cardboard v1(2014 年 Google I/O 大会上发布)的参数。
试用演示
在 HelloCardboard 中,您将在 3D 空间中查找和收集测地球体。
要查找并收集球体,请执行以下操作:
向任意方向转动头部,直到您看到浮动的形状。
直视球体。这会使它更改颜色。
按下 Cardboard 眼镜按钮即可“收集”球体。
配置设备
当用户点按齿轮图标切换 Cardboard 眼镜时,nativeSwitchViewer
方法。nativeSwitchViewer
次通话
CardboardQrCode_scanQrCodeAndSaveDeviceParams
,用于打开要扫描的窗口
观看者的二维码。查看器的镜头失真情况和其他参数只更新一次
二维码已扫描完毕。
// Called by JNI method
void HelloCardboardApp::SwitchViewer() {
CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}
启用 Android Studio x86 模拟器
如需针对 Android Studio x86 模拟器进行构建,请从
SDK 中的 build.gradle
文件
和示例:
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 扫描新的二维码时,下面的代码都会读取已保存的参数 然后使用这些物体来创建镜头失真对象,从而应用适当的镜头失真效果 附加到渲染内容:
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_);