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

Hướng dẫn này cho bạn biết cách sử dụng Cardboard SDK dành cho Android để tạo ra 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. Một chiếc điện thoại thông minh có thể hiển thị cảnh 3D với kết xuất lập thể, theo dõi và phản ứng với chuyển động của đầu, và tương tác với các ứng dụng bằng cách phát hiện thời điểm người dùng nhấn nút xem.

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

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

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

  • 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 thực thể 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" hoặc cao hơ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 các SDK đã cài đặt, hãy chuyển đến phần Lựa chọn ưu tiên > Giao diện và hành vi

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

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

SDK Cardboard được xây dựng bằng Vulkan được biên dịch trước tệp tiêu đề cho mỗi chương trình đổ bóng. Bạn có thể tìm thấy 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 của Cardboard và bản minh hoạ HelloCardboard ứng dụng 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 nơi SDK Cardboard và ứng dụng minh hoạ HelloCardboard được sao chép vào.

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

  3. Để lắp ráp Cardboard SDK, hãy nhấp đúp vào tùy chọn lắp ráp bên trong Thư mục cardboard/:sdk/Tasks/build trong thẻ Gradle (View > Tool Windows > 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 (Chạy) > Chạy... và chọn mục tiêu hellocardboard-android.

Quét mã QR

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

Nếu người dùng nhấn "BỎ QUA" và không có thông số nào đã lưu trước đó, Cardboard sẽ lưu Thông số Google Cardboard phiên bản 1 (được phát hành tại Google I/O 2014).

Xem bản minh hoạ

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

Cách tìm và thu thập một hình cầu:

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

  2. Nhìn thẳng vào hình cầu. Thao tác này sẽ khiến nút 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 giữa các thiết bị xem Cardboard, nativeSwitchViewer được gọi. nativeSwitchViewer cuộc gọi CardboardQrCode_scanQrCodeAndSaveDeviceParams sẽ mở ra cửa sổ để quét mã QR của người xem. Độ biến dạng ống kính của người xem và các thông số khác được cập nhật một lần mã QR đã được quét.

// 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 build.gradle tệp trong SDKMẫu:

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

Điều này cho phép tất cả ABI và sẽ làm tăng đáng kể kích thước của tệp được tạo Tệp .aar. Xem 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

Công cụ theo dõi chuyển động đầ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 thực thể 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ỷ bỏ công cụ theo dõi chuyển động của đầu, CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_)CardboardHeadTracker_destroy(head_tracker_) phải được gọi tương ứng. Trong "HelloCardboard" chúng tôi sẽ gọi chúng bằng 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 lần 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 chúng để tạo đối tượng méo ống kính, áp dụng độ méo ống kính thích hợp cho nội dung được 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

Kết xuất nội dung trong Cardboard bao gồm những việc sau:

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

Tạo hoạ tiết

Tất cả nội dung đều được vẽ trên một hoạ tiết, được chia thành nhiều phần cho mắt trái và mắt phải. Các phần này được khởi tạo lần lượt 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ố đến CardboardDistortionRenderer_renderEyeToDisplay.

Xem ma trận chiếu và ma trận 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 méo cho mỗi mắt và truyền lưới đó đến trình kết xuất méo:

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

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

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

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

Kết xuất nội dung

Đối với mỗi khung hình, 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 để tạo khung hiển thị ma trận chiếu 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();
}

Dùng CardboardDistortionRenderer_renderEyeToDisplay để áp dụng hiệu ứng méo sửa nội dung và hiển thị nội dung lê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_);