بدء سريع لـ Google Cardboard لنظام Android NDK

يوضِّح لك هذا الدليل كيفية استخدام Cardboard SDK لنظام التشغيل Android لإنشاء تجاربك في الواقع الافتراضي (VR).

يمكنك استخدام حزمة تطوير البرامج (SDK) في Cardboard لتحويل هاتف ذكي إلى نظام واقع افتراضي. يمكن للهاتف الذكي عرض مشاهد ثلاثية الأبعاد مع عرض مجسم، وتتبُّع حركات الرأس والتفاعل معها، والتفاعل مع التطبيقات من خلال رصد الحالات التي يضغط فيها المستخدم على زر العارض.

للبدء، ستستخدم HelloCardboard، وهي لعبة تجريبية تعرض الميزات الأساسية لحزمة تطوير البرامج (SDK) من Cardboard. في اللعبة، ينظر المستخدمون في عالم افتراضي للعثور على العناصر وجمعها. وتوضِّح لك كيفية:

  • إعداد بيئة التطوير
  • تنزيل التطبيق التجريبي وإنشاؤه
  • امسح ضوئيًا رمز الاستجابة السريعة لعارض Cardboard لحفظ معلماته.
  • تتبع حركات رأس المستخدم
  • عرض صور مجسّمة من خلال ضبط مصفوفة عرض صحيحة لكل عين

يستخدم HelloCardboard ملف Android NDK. كل طريقة مدمجة مع المحتوى هي:

  • مرتبطة بشكل فريد بأسلوب فئة HelloCardboardApp
  • إنشاء مثيل لذلك الفئة أو حذفه

إعداد بيئة التطوير

متطلبات الأجهزة:

  • جهاز Android يعمل بنظام التشغيل Android 8.0 "Oreo" (المستوى 26 من واجهة برمجة التطبيقات) أو إصدار أحدث
  • نظّارة Cardboard

متطلّبات البرامج:

  • الإصدار 2022.1.1 "Electric Eel" أو الإصدارات الأحدث من Android Studio
  • حزمة تطوير البرامج (SDK) لنظام التشغيل Android 13.0 "Tiramisu" (المستوى 33 لواجهة برمجة التطبيقات) أو إصدار أحدث
  • أحدث إصدار من إطار عمل Android NDK

    لمراجعة حِزم SDK المثبَّتة أو تحديثها، يُرجى الانتقال إلى الإعدادات المفضّلة > المظهر والسلوك.

    System Settings (إعدادات النظام) > Android SDK (حزمة تطوير البرامج (SDK) لنظام التشغيل Android) في Android Studio.

تنزيل التطبيق التجريبي وإنشاؤه

تم تصميم Cardboard SDK باستخدام ملف رأس Vulkan مجمّع مسبقًا لكلّ أداة تظليل. يمكن العثور على خطوات إنشاء ملفات العناوين من البداية هنا.

  1. شغِّل الأمر التالي لاستنساخ تطبيق Cardboard SDK وتطبيق HelloCardboard التجريبي من GitHub:

    git clone https://github.com/googlevr/cardboard.git
  2. في "استوديو Android"، اختَر فتح مشروع استوديو Android حالي، ثم اختَر الدليل الذي تم نسخ تطبيق Cardboard SDK وتطبيق HelloCardboard التجريبي إليه.

    سيظهر الرمز الخاص بك في نافذة "المشروع" في "استوديو Android".

  3. لتجميع حزمة تطوير البرامج (SDK) من Cardboard، انقر مرّتين على خيار التجميع ضمن المجلد cardboard/:sdk/Tasks/build في علامة التبويب Gradle (عرض > أداة Windows > Gradle).

  4. شغِّل تطبيق HelloCardboard التجريبي على هاتفك من خلال تحديد تشغيل > تشغيل... وتحديد هدف hellocardboard-android.

المسح الضوئي لرمز الاستجابة السريعة

لحفظ معلَمات الجهاز، امسح رمز الاستجابة السريعة ضوئيًا على نظّارة Cardboard:

إذا ضغط المستخدم على "التخطّي" ولم تكن هناك معلمات محفوظة سابقًا، يحفظ Cardboard معلَمات Google Cardboard v1 (الذي تم إطلاقه في مؤتمر Google I/O 2014).

تجربة العرض التوضيحي

في HelloCardboard، ستبحث عن المجالات الجيوديسية وتجمعها في مساحة ثلاثية الأبعاد.

للبحث عن كرة وجمعها:

  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 للحصول على مزيد من المعلومات.

تتبُّع حركة الرأس

إنشاء أداة تتبُّع للرأس

يتم إنشاء أداة تتبُّع الرأس مرة واحدة في طريقة إنشاء 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_);