การเริ่มต้นใช้งาน Google Cardboard สำหรับ Android NDK อย่างรวดเร็ว

คู่มือนี้จะแสดงวิธีใช้ Cardboard SDK สำหรับ Android เพื่อสร้างประสบการณ์ Virtual Reality (VR) ของคุณเอง

คุณใช้ Cardboard SDK เพื่อเปลี่ยนสมาร์ทโฟนเป็นแพลตฟอร์ม VR ได้ สมาร์ทโฟน สามารถแสดงฉาก 3 มิติพร้อมการแสดงภาพสามมิติ ติดตามและตอบสนองการเคลื่อนไหวของศีรษะ และโต้ตอบกับแอปด้วยการตรวจจับเมื่อผู้ใช้กดปุ่มบนแว่น

ในการเริ่มต้นใช้งาน คุณจะใช้ HelloCardboard ซึ่งเป็นเกมสาธิตที่สาธิตฟีเจอร์หลักของ Cardboard SDK ในเกม ผู้ใช้จะมองไปรอบโลกเสมือนเพื่อค้นหาและ เก็บรวบรวมวัตถุ ซึ่งจะแสดงวิธีการต่อไปนี้

  • ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
  • ดาวน์โหลดและสร้างแอปเดโม
  • สแกนคิวอาร์โค้ดของแว่น Cardboard เพื่อบันทึกพารามิเตอร์
  • ติดตามการเคลื่อนไหวศีรษะของผู้ใช้
  • แสดงภาพสามมิติโดยการตั้งค่าเมทริกซ์การฉายภาพที่ถูกต้องสำหรับตาแต่ละข้าง

HelloCardboard ใช้ Android NDK วิธีการแบบเนทีฟทั้งหมดมีดังนี้

  • มีขอบเขตไม่ซ้ำกันสำหรับเมธอดคลาส HelloCardboardApp หรือ
  • สร้างหรือลบอินสแตนซ์ของคลาสนั้น

ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์

ข้อกำหนดเกี่ยวกับฮาร์ดแวร์

  • อุปกรณ์ Android ที่ใช้ Android 8.0 "Oreo" (API ระดับ 26) ขึ้นไป
  • แว่น Cardboard

ข้อกำหนดของซอฟต์แวร์

  • Android Studio เวอร์ชัน 2022.1.1 "Electric Eel" ขึ้นไป
  • Android SDK 13.0 "Tiramisu" (API ระดับ 33) ขึ้นไป
  • เฟรมเวิร์ก Android NDK เวอร์ชันล่าสุด

    หากต้องการตรวจสอบหรืออัปเดต SDK ที่ติดตั้ง ให้ไปที่ค่ากำหนด > ลักษณะที่ปรากฏและพฤติกรรม

    การตั้งค่าระบบ > Android SDK ใน Android Studio

ดาวน์โหลดและสร้างแอปเดโม

Cardboard SDK สร้างขึ้นโดยใช้ไฟล์ส่วนหัว Vulkan ที่คอมไพล์ไว้ล่วงหน้าสำหรับตัวปรับแสงเงาแต่ละตัว ดูขั้นตอนการสร้างไฟล์ส่วนหัวใหม่ตั้งแต่ต้นได้ที่นี่

  1. เรียกใช้คำสั่งต่อไปนี้เพื่อโคลน SDK ของ Cardboard และแอปเดโม HelloCardboard จาก GitHub

    git clone https://github.com/googlevr/cardboard.git
  2. ใน Android Studio ให้เลือกเปิดโปรเจ็กต์ Android Studio ที่มีอยู่ จากนั้นเลือกไดเรกทอรีที่มีการโคลนแอป Cardboard SDK และแอปสาธิต HelloCardboard

    รหัสจะปรากฏในหน้าต่างโปรเจ็กต์ใน Android Studio

  3. หากต้องการประกอบ Cardboard SDK ให้ดับเบิลคลิกตัวเลือกประกอบภายในโฟลเดอร์ cardboard/:sdk/Tasks/build ในแท็บ Gradle (มุมมอง > หน้าต่างเครื่องมือ > Gradle)

  4. เรียกใช้แอปสาธิต HelloCardboard บนโทรศัพท์โดยเลือก Run > Run... และเลือกเป้าหมาย hellocardboard-android

สแกนคิวอาร์โค้ด

หากต้องการบันทึกพารามิเตอร์ของอุปกรณ์ ให้สแกนคิวอาร์โค้ดบนแว่น Cardboard ดังนี้

หากผู้ใช้กด "ข้าม" และไม่มีพารามิเตอร์ที่บันทึกไว้ก่อนหน้านี้ Cardboard จะบันทึกพารามิเตอร์ Google Cardboard v1 (เปิดตัวที่ Google I/O 2014)

ลองใช้เดโม

ใน HelloCardboard คุณจะค้นหาและรวบรวมทรงกลมลูกโลกในพื้นที่ 3 มิติ

วิธีค้นหาและรวบรวมทรงกลม

  1. ขยับศีรษะไปในทิศทางใดก็ได้จนกว่าจะเห็นรูปร่างลอย

  2. มองตรงไปที่ทรงกลม ซึ่งจะทำให้ภาพเปลี่ยนสี

  3. กดปุ่มแว่น Cardboard เพื่อ "รวบรวม" ทรงกลม

กำหนดค่าอุปกรณ์

เมื่อผู้ใช้แตะไอคอนรูปเฟืองเพื่อเปลี่ยนแว่น Cardboard ระบบจะเรียกใช้เมธอด nativeSwitchViewer โทร nativeSwitchViewer ครั้ง CardboardQrCode_scanQrCodeAndSaveDeviceParams ซึ่งจะเปิดหน้าต่างเพื่อสแกนคิวอาร์โค้ดของผู้ชม การบิดเบี้ยวของเลนส์และพารามิเตอร์อื่นๆ ของผู้ชมจะอัปเดตเมื่อสแกนคิวอาร์โค้ดแล้ว

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

เปิดใช้โปรแกรมจำลอง Android Studio x86

หากต้องการสร้างสำหรับโปรแกรมจำลอง Android Studio x86 ให้นำบรรทัดต่อไปนี้ออกจากไฟล์ build.gradle ใน SDK และตัวอย่าง

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

ซึ่งจะเปิดใช้ ABI ทั้งหมดและจะเพิ่มขนาดไฟล์ .aar ที่สร้างขึ้นอย่างมาก ดูข้อมูลเพิ่มเติมที่ ABI ของ Android

การติดตามการเคลื่อนไหวของศีรษะ

สร้างเครื่องมือติดตามศีรษะ

อุปกรณ์ติดตามศีรษะจะสร้างขึ้น 1 ครั้งในตัวสร้างของ 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);

สร้างโหมดแสดงภาพและตั้งค่าตาข่ายการบิดเบี้ยวที่ถูกต้อง

โหมดแสดงภาพต้องเริ่มต้นเพียงครั้งเดียว เมื่อสร้างตัวแสดงผลแล้ว ให้ตั้งค่าตาข่ายการบิดเบี้ยวใหม่สำหรับตาซ้ายและขวาตามค่า 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_);