Guía de inicio rápido de Google Cardboard para iOS

En esta guía, se muestra cómo usar el SDK de Cardboard para iOS a fin de crear tus propias experiencias de realidad virtual (RV).

Puedes usar el SDK de Cardboard para convertir un smartphone en una plataforma de RV. Un smartphone puede mostrar escenas en 3D con renderización estereoscópica, hacer un seguimiento de los movimientos de la cabeza y reaccionar a ellos, e interactuar con las apps detectando cuándo el usuario presiona el botón del visor.

Para comenzar, usarás HelloCardboard, un juego de demostración que muestra las funciones principales del SDK de Cardboard. En el juego, los usuarios exploran un mundo virtual para encontrar y recolectar objetos. Se muestra cómo realizar las siguientes acciones:

  • Cómo configurar tu entorno de desarrollo
  • Cómo descargar y compilar la app de demostración
  • Escanea el código QR de un visor Cardboard para guardar sus parámetros
  • Seguimiento de los movimientos de la cabeza del usuario
  • Renderiza imágenes estereoscópicas configurando la distorsión correcta para cada ojo.

Cómo configurar tu entorno de desarrollo

Requisitos de hardware:

Requisitos de software:

Cómo descargar y compilar la app de demostración

El SDK de Cardboard se compila con archivos de origen C++ de búferes de protocolo compilados previamente. Aquí encontrarás los pasos para compilar los archivos fuente desde cero.

  1. Clona el SDK de Cardboard y la app de demostración de Hello Cardboard desde GitHub ejecutando este comando:

    git clone https://github.com/googlevr/cardboard.git
  2. Para instalar la dependencia de búferes de protocolo en el proyecto de Xcode, ejecuta este comando en la raíz del repositorio:

    pod install
  3. Abre el lugar de trabajo de Cardboard (Cardboard.xcworkspace) en Xcode.

  4. Cambia el ID del paquete de la app para que puedas firmarla con tu equipo.

  5. Navega a SDK > Build Phases > Link Binary With Libraries.

    1. Quita libPods-sdk.a de la lista. Para ello, selecciónalo y haz clic en el botón “-”.
    2. Para agregar libProtobuf-C++.a a la lista, haz clic en el botón “+” y selecciónalo. Si aparece un mensaje que sugiere usar un XCFramework, haz clic en "Add Anyway".
  6. Haz clic en Ejecutar.

Escanea el código QR

Para guardar los parámetros del dispositivo, escanea el código QR en el visor Cardboard de la siguiente manera:

Probar demostración

En HelloCardboard, buscarás y recolectarás esferas geodésicas en un espacio 3D.

Para buscar y recopilar una esfera:

  1. Mueve la cabeza en cualquier dirección hasta que veas una esfera flotante.

  2. Mira directamente a la esfera. Esto hace que cambie de color.

  3. Presiona el botón del visor Cardboard para "recopilar" la esfera.

Configura el dispositivo

Cuando el usuario presiona el ícono de ajustes para cambiar de visor Cardboard, se llama al método didTapSwitchButton en HelloCardboardOverlayView.

- (void)didTapSwitchButton:(id)sender {
  if ([self.delegate respondsToSelector:@selector(didTapBackButton)]) {
    [self.delegate didChangeViewerProfile];
  }
  self.settingsBackgroundView.hidden = YES;
}

Esto llama a CardboardQrCode_scanQrCodeAndSaveDeviceParams, que abre la ventana para escanear el código QR del usuario. Cuando el usuario escanea el código QR, se actualizan los parámetros de distorsión del dispositivo.

- (void)switchViewer {
  CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}

- (void)didChangeViewerProfile {
  [self pauseCardboard];
  [self switchViewer];
  [self resumeCardboard];
}

Seguimiento de cabeza

Crear monitor de cabeza

El seguimiento de cabeza se crea una vez en el método viewDidLoad de HelloCardboardViewController:

_cardboardHeadTracker = CardboardHeadTracker_create();

Pausar y reanudar el seguimiento de cabeza

Los métodos pauseCardboard y resumeCardboard de la clase HelloCardboardViewController pausan y reanudan el seguimiento de cabeza, respectivamente. resumeCardboard también establece la marca _updateParams, que hace que los parámetros del dispositivo se actualicen en la siguiente llamada de dibujo.

- (void)pauseCardboard {
  self.paused = true;
  CardboardHeadTracker_pause(_cardboardHeadTracker);
}

- (void)resumeCardboard {
  // Parameters may have changed.
  _updateParams = YES;

  // Check for device parameters existence in app storage. If they're missing,
  // we must scan a Cardboard QR code and save the obtained parameters.
  uint8_t *buffer;
  int size;
  CardboardQrCode_getSavedDeviceParams(&buffer, &size);
  if (size == 0) {
    [self switchViewer];
  }
  CardboardQrCode_destroy(buffer);

  CardboardHeadTracker_resume(_cardboardHeadTracker);
  self.paused = false;
}

Distorsión del lente

Cada vez que Cardboard escanea un código QR nuevo, el siguiente código lee los parámetros guardados y los usa para crear el objeto de distorsión de la lente, que aplica la distorsión adecuada del lente al contenido renderizado:

CardboardQrCode_getSavedDeviceParams(&encodedDeviceParams, &size);

// Create CardboardLensDistortion.
CardboardLensDistortion_destroy(_cardboardLensDistortion);
_cardboardLensDistortion =
    CardboardLensDistortion_create(encodedDeviceParams, size, width, height);

// Initialize HelloCardboardRenderer.
_renderer.reset(new cardboard::hello_cardboard::HelloCardboardRenderer(
      _cardboardLensDistortion, _cardboardHeadTracker, width, height));

Renderización

La renderización de contenido en Cardboard implica lo siguiente:

  • Crear texturas
  • Cómo obtener matrices de vista y proyección para los ojos izquierdo y derecho
  • Cómo crear el procesador y configurar la malla de distorsión
  • Cómo renderizar cada fotograma

Crea texturas

El contenido se dibuja en una textura, que se divide en secciones para el ojo izquierdo y el derecho. Estas secciones se inicializan en _leftEyeTexture y _rightEyeTexture, respectivamente. En la app de ejemplo, se usa una sola textura para ambos ojos, pero también es posible crear una textura separada para cada ojo.

// Generate texture to render left and right eyes.
glGenTextures(1, &_eyeTexture);
glBindTexture(GL_TEXTURE_2D, _eyeTexture);
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, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

_leftEyeTexture.texture = _eyeTexture;
_leftEyeTexture.left_u = 0;
_leftEyeTexture.right_u = 0.5;
_leftEyeTexture.top_v = 1;
_leftEyeTexture.bottom_v = 0;

_rightEyeTexture.texture = _eyeTexture;
_rightEyeTexture.left_u = 0.5;
_rightEyeTexture.right_u = 1;
_rightEyeTexture.top_v = 1;
_rightEyeTexture.bottom_v = 0;
CheckGLError("Create Eye textures");

Estas texturas se pasan como parámetros a CardboardDistortionRenderer_renderEyeToDisplay.

Obtener matrices de vistas y de proyección para el ojo izquierdo y el derecho

Primero, recupera las matrices de los ojos para el ojo izquierdo y el derecho:

CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kLeft, _eyeMatrices[kLeft]);
CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kRight, _eyeMatrices[kRight]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kLeft, kZNear, kZFar,
                                            _projMatrices[kLeft]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kRight, kZNear, kZFar,
                                            _projMatrices[kRight]);

A continuación, obtén las mallas de distorsión para cada uno de los ojos y pásalas al procesador de distorsión:

CardboardLensDistortion_getDistortionMesh(_lensDistortion, kLeft, &leftMesh);
CardboardLensDistortion_getDistortionMesh(_lensDistortion, kRight, &rightMesh);

Cómo crear el renderizador y establecer la malla de distorsión correcta

El procesador debe inicializarse solo una vez. Una vez que se haya creado el procesador, configura la nueva malla de distorsión para los ojos izquierdo y derecho según los valores de la malla que muestra la función CardboardLensDistortion_getDistortionMesh.

_distortionRenderer = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(_distortionRenderer, &leftMesh, kLeft);
CardboardDistortionRenderer_setMesh(_distortionRenderer, &rightMesh, kRight);

Cómo procesar el contenido

Recupera la orientación actual de la cabeza de CardboardHeadTracker_getPose:

CardboardHeadTracker_getPose(_headTracker, targetTime, position, orientation);
_headView =
    GLKMatrix4Multiply(GLKMatrix4MakeTranslation(position[0], position[1], position[2]),
                       GLKMatrix4MakeWithQuaternion(GLKQuaternionMakeWithArray(orientation)));

Usa la orientación actual de la cabeza con las matrices de vista y proyección para componer una matriz de proyección de vistas, y úsalas para renderizar el contenido del mundo para cada uno de los ojos:

// Draw left eye.
glViewport(0, 0, _width / 2.0, _height);
glScissor(0, 0, _width / 2.0, _height);
DrawWorld(_leftEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kLeft]));

// Draw right eye.
glViewport(_width / 2.0, 0, _width / 2.0, _height);
glScissor(_width / 2.0, 0, _width / 2.0, _height);
DrawWorld(_rightEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kRight]));

Usa CardboardDistortionRenderer_renderEyeToDisplay para aplicar la corrección de distorsión al contenido y renderizarlo en la pantalla.

CardboardDistortionRenderer_renderEyeToDisplay(_distortionRenderer, renderTarget, /*x=*/0,
                                               /*y=*/0, _width, _height, &_leftEyeTexture,
                                               &_rightEyeTexture);