Hướng dẫn nhanh về Google Cardboard dành cho Android NDK

Tài liệu hướng dẫn này trình bày cách sử dụng Cardboard SDK dành cho Android để tạo trải nghiệm Thực tế ảo (VR) của riêng bạn.

Bạn có thể sử dụng SDK của Cardboard để biến điện thoại thông minh thành nền tảng thực tế ảo. Điện thoại thông minh có thể hiển thị cảnh 3D bằng phương thức kết xuất lập thể, theo dõi và phản ứng với chuyển động của đầu, cũng như tương tác với các ứng dụng bằng cách phát hiện khi người dùng nhấn nút trình xem.

Để bắt đầu, bạn sẽ sử dụng HelloCardboard, một trò chơi minh hoạ minh hoạ các tính năng cốt lõi của SDK Cardboard. Trong trò chơi, người dùng sẽ nhìn xung quanh một thế giới ảo để tìm và thu thập các đối tượng. Hướng dẫn này sẽ hướng dẫn bạn cách:

  • Thiết lập môi trường phát triển
  • Tải và tạo ứng dụng minh hoạ
  • Quét mã QR của thiết bị xem Cardboard để lưu các thông số của thiết bị
  • Theo dõi cử động đầu của người dùng
  • Kết xuất hình ảnh nổi bằng cách đặt ma trận chiếu khung nhìn chính xác cho mỗi mắt

HelloCardboard sử dụng Android NDK. Mọi phương thức gốc đều:

  • Được giới hạn duy nhất với một phương thức lớp HelloCardboardApp hoặc
  • Tạo hoặc xoá một bản sao của lớp đó

Thiết lập môi trường phát triển

Yêu cầu về phần cứng:

Yêu cầu về phần mềm:

  • Android Studio phiên bản 2022.1.1 "Electric Eel" trở lên
  • SDK Android 13.0 "Tiramisu" (API cấp 33) trở lên
  • Phiên bản mới nhất của khung Android NDK

    Để xem lại hoặc cập nhật SDK đã cài đặt, hãy chuyển đến Lựa chọn ưu tiên > Giao diện và hành vi

    System Settings (Cài đặt hệ thống) > Android SDK trong Android Studio.

Tải và tạo ứng dụng minh hoạ

SDK Cardboard được xây dựng bằng cách sử dụng một tệp tiêu đề Vulkan được biên dịch trước cho mỗi chương trình đổ bóng. Bạn có thể xem các bước tạo tệp tiêu đề từ đầu tại đây.

  1. Chạy lệnh sau để sao chép SDK Cardboard và ứng dụng minh hoạ HelloCardboard từ GitHub:

    git clone https://github.com/googlevr/cardboard.git
  2. Trong Android Studio, hãy chọn Open an existing Android Studio Project (Mở một dự án Android Studio hiện có), sau đó chọn thư mục sao chép SDK Cardboard và ứng dụng minh hoạ HelloCardboard vào đó.

    Mã nguồn của bạn sẽ xuất hiện trong cửa sổ Dự án trong Android Studio.

  3. Để cài đặt SDK của Cardboard, hãy nhấp đúp vào tuỳ chọn tập hợp trong thư mục cardboard/:sdk/Tasks/build trong thẻ Gradle (Xem > Cửa sổ công cụ > Gradle).

  4. Chạy ứng dụng minh hoạ HelloCardboard trên điện thoại bằng cách chọn Run > Run... (Chạy > Chạy...) rồi chọn mục tiêu hellocardboard-android.

Quét mã QR

Để lưu các thông số thiết bị, hãy quét mã QR trên thiết bị xem Cardboard:

Nếu người dùng nhấn vào "SKIP" và chưa có thông số nào được lưu trước đó, thì Cardboard sẽ lưu các thông số của Google Cardboard phiên bản 1 (đã ra mắt tại Google I/O 2014).

Dùng thử bản trình diễn

Trong HelloCardboard, bạn sẽ tìm kiếm và thu thập các quả cầu trắc địa trong không gian 3D.

Để tìm và thu thập hình cầu:

  1. Di chuyển đầu xung quanh theo bất kỳ hướng nào cho đến khi bạn thấy một hình dạng nổi.

  2. Nhìn thẳng vào quả cầu. Thao tác này sẽ làm thay đổi màu sắc.

  3. Nhấn nút thiết bị xem Cardboard để "thu thập" hình cầu.

Định cấu hình thiết bị

Khi người dùng nhấn vào biểu tượng bánh răng để chuyển đổi thiết bị xem Cardboard, phương thức nativeSwitchViewer sẽ được gọi. nativeSwitchViewer gọi CardboardQrCode_scanQrCodeAndSaveDeviceParams, thao tác này sẽ mở ra một cửa sổ để quét mã QR của người xem. Độ méo ống kính của người xem và các thông số khác sẽ được cập nhật sau khi quét mã QR.

// Called by JNI method
void HelloCardboardApp::SwitchViewer() {
  CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}

Bật trình mô phỏng Android Studio x86

Để tạo bản dựng cho trình mô phỏng Android Studio x86, hãy xoá dòng sau khỏi tệp build.gradle trong SDKMẫu:

abiFilters 'armeabi-v7a', 'arm64-v8a'

Thao tác này sẽ bật tất cả ABI và sẽ tăng đáng kể kích thước của tệp .aar được tạo. Xem phần ABI Android để biết thêm thông tin.

Theo dõi chuyển động của đầu

Tạo thiết bị theo dõi chuyển động của đầu

Trình theo dõi đầu được tạo một lần trong hàm khởi tạo của HelloCardboardApp:

HelloCardboardApp::HelloCardboardApp(JavaVM* vm, jobject obj, jobject asset_mgr_obj) {
  Cardboard_initializeAndroid(vm, obj); // Must be called in constructor
  head_tracker_ = CardboardHeadTracker_create();
}

Khi VrActivity được tạo, một bản sao của lớp HelloCardboardApp sẽ được tạo bằng cách gọi phương thức nativeOnCreate:

public void onCreate(Bundle savedInstance) {
  super.onCreate(savedInstance);
  nativeApp = nativeOnCreate(getAssets());
  //...
}

Tạm dừng và tiếp tục thiết bị theo dõi chuyển động của đầu

Để tạm dừng, tiếp tục và huỷ trình theo dõi chuyển động của đầu, bạn phải gọi CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_)CardboardHeadTracker_destroy(head_tracker_) tương ứng. Trong ứng dụng "HelloCardboard", chúng ta gọi các lớp này trong nativeOnPause, nativeOnResumenativeOnDestroy:

// 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;
}

Biến dạng ống kính

Mỗi khi Cardboard quét một mã QR mới, mã sau đây sẽ đọc các thông số đã lưu và sử dụng các thông số đó để tạo đối tượng méo ống kính, từ đó áp dụng độ méo ống kính thích hợp cho nội dung đã kết xuất:

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

CardboardLensDistortion_destroy(lens_distortion_);
lens_distortion_ = CardboardLensDistortion_create(
    buffer, size, screen_width_, screen_height_);

CardboardQrCode_destroy(buffer);

Kết xuất

Quá trình kết xuất nội dung trong Cardboard bao gồm những yếu tố sau:

  • Tạo hoạ tiết
  • Lấy ma trận nhìn và chiếu cho mắt trái và mắt phải
  • Tạo trình kết xuất đồ hoạ và thiết lập lưới biến dạng
  • Kết xuất từng khung

Tạo hoạ tiết

Tất cả nội dung được vẽ trên một hoạ tiết, được chia thành các phần dành cho mắt trái và phải. Các phần này lần lượt được khởi tạo trong _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");
}

Các hoạ tiết này được truyền dưới dạng tham số cho CardboardDistortionRenderer_renderEyeToDisplay.

Lấy ma trận nhìn và chiếu cho mắt trái và mắt phải

Trước tiên, hãy truy xuất ma trận mắt cho mắt trái và mắt phải:

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]);

Tiếp theo, hãy lấy lưới biến dạng cho mỗi mắt rồi truyền đến trình kết xuất biến dạng:

CardboardLensDistortion_getDistortionMesh(lens_distortion_, kLeft, &left_mesh);
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kRight, &right_mesh);

Tạo trình kết xuất đồ hoạ và thiết lập đúng lưới méo

Trình kết xuất chỉ cần được khởi chạy một lần. Sau khi tạo trình kết xuất, hãy thiết lập lưới méo mới cho mắt trái và mắt phải theo các giá trị lưới được hàm CardboardLensDistortion_getDistortionMesh trả về.

distortion_renderer_ = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(distortion_renderer_, &left_mesh, kLeft);
CardboardDistortionRenderer_setMesh(distortion_renderer_, &right_mesh, kRight);

Hiển thị nội dung

Đối với mỗi khung, hãy truy xuất hướng đầu hiện tại từ CardboardHeadTracker_getPose:

CardboardHeadTracker_getPose(head_tracker_, monotonic_time_nano, &out_position[0], &out_orientation[0]);

Sử dụng hướng đầu hiện tại với ma trận khung hiển thị và ma trận chiếu để lập ma trận chiếu khung hiển thị cho mỗi mắt và kết xuất nội dung lên màn hình:

// 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();
}

Sử dụng CardboardDistortionRenderer_renderEyeToDisplay để áp dụng tính năng chỉnh sửa độ méo cho nội dung và hiển thị nội dung đó trên màn hình.

// Render
CardboardDistortionRenderer_renderEyeToDisplay(
    distortion_renderer_, /* target_display = */ 0, /* x = */ 0, /* y = */ 0,
    screen_width_, screen_height_, &left_eye_texture_description_,
    &right_eye_texture_description_);