En esta guía, se muestra cómo usar el SDK de Cardboard para Android y 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, y detectar cuando el usuario presiona el botón del visor para interactuar con las apps.
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. En él, se muestra cómo hacer lo siguiente:
- Configura tu entorno de desarrollo
- Descarga y compila la app de demostración
- Cómo escanear el código QR de un visor Cardboard para guardar sus parámetros
- Realizar un seguimiento de los movimientos de la cabeza del usuario
- Renderiza imágenes estereoscópicas configurando la matriz de proyección de vista correcta para cada ojo
HelloCardboard usa el NDK de Android. Todos los métodos nativos cumplen con las siguientes condiciones:
- Vinculado de forma única a un método de clase
HelloCardboardApp
- Crea o borra una instancia de esa clase
Configura tu entorno de desarrollo
Requisitos de hardware:
- Un dispositivo Android que ejecute Android 8.0 "Oreo" (nivel de API 26) o una versión posterior
- Visor Cardboard
Requisitos de software:
- Versión Android Studio 2024.1.2 "Actualización de funciones de Koala" o posterior
- SDK de Android 15.0 "Vanilla Ice Cream" (nivel de API 35) o una versión posterior
La versión más reciente del framework del NDK de Android
Para revisar o actualizar los SDKs instalados, ve a Preferences > Appearance and Behavior.
System Settings > Android SDK en Android Studio
Descarga y compila la app de demostración
El SDK de Cardboard se compila con un archivo de encabezado Vulkan precompilado para cada sombreador. Aquí encontrarás los pasos para compilar los archivos de encabezado desde cero.
Ejecuta el siguiente comando para clonar el SDK de Cardboard y la app de demostración de HelloCardboard desde GitHub:
git clone https://github.com/googlevr/cardboard.git
En Android Studio, selecciona Open an existing Android Studio Project y, luego, selecciona el directorio en el que se clonaron el SDK de Cardboard y la app de demostración HelloCardboard.
Tu código aparecerá en la ventana Project de Android Studio.
Para ensamblar el SDK de Cardboard, haz doble clic en la opción assemble dentro de la carpeta cardboard/:sdk/Tasks/build en la pestaña Gradle (View > Tool Windows > Gradle).
Para ejecutar la app de demostración de HelloCardboard en tu teléfono, selecciona Run > Run… y elige el destino
hellocardboard-android
.
Escanea el código QR
Para guardar los parámetros del dispositivo, escanea el código QR del visor Cardboard:
Si el usuario presiona "SKIP" y no hay parámetros guardados anteriormente, Cardboard guarda los parámetros de Google Cardboard v1 (lanzado en Google I/O 2014).
Probar la demostración
En HelloCardboard, buscarás y recopilarás esferas geodésicas en el espacio 3D.
Para encontrar y recoger una esfera, haz lo siguiente:
Mueve la cabeza en cualquier dirección hasta que veas una forma flotante.
Mira directamente la esfera. Esto hace que cambie de color.
Presiona el botón del visor de Cardboard para "recoger" la esfera.
Configura el dispositivo
Cuando el usuario presiona el ícono de ajustes para cambiar los visores de Cardboard, se llama al método nativeSwitchViewer
. nativeSwitchViewer
llama a CardboardQrCode_scanQrCodeAndSaveDeviceParams
, que abre la ventana para escanear el código QR del usuario. La distorsión del lente del visor y otros parámetros se actualizan una vez que se escanea el código QR.
// Called by JNI method
void HelloCardboardApp::SwitchViewer() {
CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}
Habilita el emulador x86 de Android Studio
Para compilar el emulador x86 de Android Studio, quita la siguiente línea de los archivos build.gradle
en SDK y Sample:
abiFilters 'armeabi-v7a', 'arm64-v8a'
Esto habilita todas las ABIs y aumentará significativamente el tamaño del archivo .aar
generado. Consulta ABI de Android para obtener más información.
Monitoreo de cabeza
Cómo crear un dispositivo de seguimiento de la cabeza
El dispositivo de seguimiento de la cabeza se crea una vez en el constructor de HelloCardboardApp
:
HelloCardboardApp::HelloCardboardApp(JavaVM* vm, jobject obj, jobject asset_mgr_obj) {
Cardboard_initializeAndroid(vm, obj); // Must be called in constructor
head_tracker_ = CardboardHeadTracker_create();
}
Cuando se crea VrActivity
, se genera una instancia de la clase HelloCardboardApp
llamando al método nativeOnCreate
:
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
nativeApp = nativeOnCreate(getAssets());
//...
}
Cómo pausar y reanudar el seguimiento de la cabeza
Para pausar, reanudar y destruir el dispositivo de seguimiento de la cabeza, se deben llamar a CardboardHeadTracker_pause(head_tracker_)
, CardboardHeadTracker_resume(head_tracker_)
y CardboardHeadTracker_destroy(head_tracker_)
, respectivamente. En la app de "HelloCardboard", los llamamos en nativeOnPause
, nativeOnResume
y 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;
}
Distorsión de 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 lente, que aplica la distorsión de lente adecuada al contenido renderizado:
CardboardQrCode_getSavedDeviceParams(&buffer, &size);
CardboardLensDistortion_destroy(lens_distortion_);
lens_distortion_ = CardboardLensDistortion_create(
buffer, size, screen_width_, screen_height_);
CardboardQrCode_destroy(buffer);
Renderización
La renderización de contenido en Cardboard implica lo siguiente:
- Cómo crear texturas
- Cómo obtener matrices de vista y proyección para los ojos izquierdo y derecho
- Cómo crear el renderizador y configurar la malla de distorsión
- Renderiza cada fotograma
Crea texturas
Todo el contenido se dibuja en una textura, que se divide en secciones para los ojos izquierdo y derecho.
Estas secciones se inicializan en _leftEyeTexture
y _rightEyeTexture
, respectivamente.
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");
}
Estas texturas se pasan como parámetros a CardboardDistortionRenderer_renderEyeToDisplay
.
Obtén matrices de vista y proyección para el ojo izquierdo y el derecho
Primero, recupera las matrices de los ojos izquierdo y derecho:
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]);
A continuación, obtén las mallas de distorsión para cada uno de los ojos y pásalas al renderizador de distorsión:
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kLeft, &left_mesh);
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kRight, &right_mesh);
Crea el renderizador y configura la malla de distorsión correcta
El renderizador solo debe inicializarse una vez. Una vez que se crea el renderizador, establece la nueva malla de distorsión para los ojos izquierdo y derecho según los valores de malla que se muestran en la función CardboardLensDistortion_getDistortionMesh
.
distortion_renderer_ = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(distortion_renderer_, &left_mesh, kLeft);
CardboardDistortionRenderer_setMesh(distortion_renderer_, &right_mesh, kRight);
Renderizar el contenido
Para cada fotograma, recupera la orientación actual de la cabeza desde CardboardHeadTracker_getPose
:
CardboardHeadTracker_getPose(head_tracker_, monotonic_time_nano, &out_position[0], &out_orientation[0]);
Usa la orientación actual de la cabeza con las matrices de vista y proyección para componer una matriz de proyección de vista para cada ojo y renderizar contenido en la pantalla:
// 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();
}
Usa CardboardDistortionRenderer_renderEyeToDisplay
para aplicar la corrección de distorsión al contenido y renderizarlo en la pantalla.
// Render
CardboardDistortionRenderer_renderEyeToDisplay(
distortion_renderer_, /* target_display = */ 0, /* x = */ 0, /* y = */ 0,
screen_width_, screen_height_, &left_eye_texture_description_,
&right_eye_texture_description_);