Cómo agregar video espacial a tu app

El SDK de Jetpack XR admite la reproducción de videos uno al lado del otro estereoscópicos en superficies planas. Con el video estereoscópico, cada fotograma consta de una imagen para el ojo izquierdo y otra para el ojo derecho, lo que les da a los usuarios una sensación de profundidad, también conocida como estereopsis.

Puedes renderizar videos 2D no estereoscópicos en apps para Android XR con las APIs de medios estándar que se usan para el desarrollo de Android en otros factores de forma.

Reproduce videos uno al lado del otro con Jetpack SceneCore

Con el video contiguo, cada fotograma estereoscópico se presenta como dos imágenes dispuestas horizontalmente una junto a la otra. Los fotogramas de video superior e inferior se disponen verticalmente uno junto al otro.

El video lado a lado no es un códec, sino una forma de organizar los fotogramas estereoscópicos, lo que significa que se puede codificar en cualquiera de los códecs compatibles con Android.

Puedes cargar videos uno al lado del otro con Media3 Exoplayer y, luego, renderizarlos con el nuevo SurfaceEntity. Para crear un SurfaceEntity, llama a SurfaceEntity.create, como se muestra en el siguiente ejemplo.

val stereoSurfaceEntity = SurfaceEntity.create(
    xrSession,
    SurfaceEntity.StereoMode.SIDE_BY_SIDE,
    Pose(Vector3(0.0f, 0.0f, -1.5f)),
    SurfaceEntity.CanvasShape.Quad(1.0f, 1.0f)
)
val videoUri = Uri.Builder()
    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
    .path("sbs_video.mp4")
    .build()
val mediaItem = MediaItem.fromUri(videoUri)

val exoPlayer = ExoPlayer.Builder(this).build()
exoPlayer.setVideoSurface(stereoSurfaceEntity.getSurface())
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()

Reproduce videos en MV-HEVC con Jetpack SceneCore

El estándar del códec MV-HEVC está optimizado y diseñado para video estereoscópico, lo que permite que tu app reproduzca videos envolventes de manera eficiente y con una gran calidad. Los archivos MV-HEVC tienen un flujo principal, por lo general, el ojo izquierdo, y un flujo estéreo con el otro ojo.

Al igual que con el video uno al lado del otro, puedes cargarlo con Media3 ExoPlayer y renderizarlo con SurfaceEntity. Cuando llames a SurfaceEntity.create, deberás especificar si tu archivo MV-HEVC es principal izquierdo o derecho en el parámetro stereoMode.

// Create the SurfaceEntity with the StereoMode corresponding to the MV-HEVC content
val stereoSurfaceEntity = SurfaceEntity.create(
    xrSession,
    SurfaceEntity.StereoMode.MULTIVIEW_LEFT_PRIMARY,
    Pose(Vector3(0.0f, 0.0f, -1.5f)),
    SurfaceEntity.CanvasShape.Quad(1.0f, 1.0f)
)
val videoUri = Uri.Builder()
    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
    .path("mvhevc_video.mp4")
    .build()
val mediaItem = MediaItem.fromUri(videoUri)

val exoPlayer = ExoPlayer.Builder(this).build()
exoPlayer.setVideoSurface(stereoSurfaceEntity.getSurface())
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()

Reproduce videos panorámicos de 180° y 360° con Jetpack SceneCore

SurfaceEntity admite la reproducción de videos de 180° en superficies hemisféricas y de videos de 360° en superficies esféricas. El parámetro radius hace referencia al tamaño radial de las superficies respectivas en metros de forma predeterminada.

En el siguiente código, se muestra cómo configurar SurfaceEntity para la reproducción en un hemisferio de 180° y una esfera de 360°. Cuando uses estas formas de lienzo, posiciona la superficie aprovechando la postura de la cabeza del usuario para brindar una experiencia envolvente.

// Set up the surface for playing a 180° video on a hemisphere.
val hemisphereStereoSurfaceEntity =
    SurfaceEntity.create(
        xrSession,
        SurfaceEntity.StereoMode.SIDE_BY_SIDE,
        xrSession.scene.spatialUser.head?.transformPoseTo(
            Pose.Identity,
            xrSession.scene.activitySpace
        )!!,
        SurfaceEntity.CanvasShape.Vr180Hemisphere(1.0f),
    )
// ... and use the surface for playing the media.

// Set up the surface for playing a 360° video on a sphere.
val sphereStereoSurfaceEntity =
    SurfaceEntity.create(
        xrSession,
        SurfaceEntity.StereoMode.TOP_BOTTOM,
        xrSession.scene.spatialUser.head?.transformPoseTo(
            Pose.Identity,
            xrSession.scene.activitySpace
        )!!,
        SurfaceEntity.CanvasShape.Vr360Sphere(1.0f),
    )
// ... and use the surface for playing the media.

Control avanzado de SurfaceEntity

Para tener un control más avanzado sobre la renderización de imágenes y videos, como la aplicación de efectos de materiales personalizados, puedes trabajar directamente con SurfaceEntity desde la biblioteca de SceneCore.

En las siguientes secciones, se describen algunas de las funciones avanzadas disponibles en SurfaceEntity.

Cómo aplicar difuminado en los bordes

Suaviza los bordes de la superficie para que se combine con el entorno configurando la propiedad edgeFeather.

// Create a SurfaceEntity.
val surfaceEntity = SurfaceEntity.create(
    session = xrSession,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f))
)

// Feather the edges of the surface.
surfaceEntity.edgeFeather =
    SurfaceEntity.EdgeFeatheringParams.SmoothFeather(0.1f, 0.1f)

Cómo aplicar una máscara alfa

Aplica una máscara alfa para crear superficies no rectangulares o agregar efectos de transparencia. Primero, carga un Texture desde un recurso y, luego, asígnalo a la propiedad primaryAlphaMaskTexture:

// Create a SurfaceEntity.
val surfaceEntity = SurfaceEntity.create(
    session = xrSession,
    pose = Pose(Vector3(0.0f, 0.0f, -1.5f))
)

// Load the texture in a coroutine scope.
activity.lifecycleScope.launch {
    val alphaMaskTexture =
        Texture.create(
            xrSession,
            Paths.get("textures", "alpha_mask.png"),
            TextureSampler.create()
        )

    // Apply the alpha mask.
    surfaceEntity.primaryAlphaMaskTexture = alphaMaskTexture

    // To remove the mask, set the property to null.
    surfaceEntity.primaryAlphaMaskTexture = null
}

Reproduce videos espaciales con Jetpack Compose XR

Si te interesa aprender a reproducir videos con Jetpack Compose para XR, consulta cómo agregar una superficie para contenido de imágenes o videos.