Dodawanie dźwięku przestrzennego do aplikacji

Pakiet Jetpack XR SDK obsługuje odtwarzanie stereoskopowych filmów wideo typu side-by-side na płaskich powierzchniach. W przypadku filmów stereoskopowych każda klatka składa się z obrazu dla lewego i prawego oka, co daje widzom poczucie głębi, zwane też stereopsją.

W aplikacjach na Androida XR możesz renderować niestoskopowe filmy 2D za pomocą standardowych interfejsów API multimediów używanych do tworzenia aplikacji na Androida na inne formaty.

Odtwarzanie filmów obok siebie za pomocą Jetpack SceneCore

W przypadku filmów wyświetlanych obok siebie każda klatka stereoskopowa jest przedstawiana jako 2 obrazy ułożone obok siebie w poziomie. Klatki wideo są ułożone jedna pod drugą.

Wideo obok siebie nie jest kodekiem, ale sposobem organizacji klatek stereoskopowych, co oznacza, że można je zakodować w dowolnym kodeku obsługiwanym przez Androida.

Możesz wczytać film w formacie side-by-side za pomocą Media3 Exoplayera, a następnie wyrenderować go za pomocą nowego komponentu SurfaceEntity. Aby utworzyć SurfaceEntity, wywołaj SurfaceEntity.create, jak pokazano w tym przykładzie.

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()

Odtwarzanie filmów MV-HEVC za pomocą Jetpack SceneCore

Standard kodeka MV-HEVC jest zoptymalizowany i przeznaczony do wideo stereoskopowego, dzięki czemu aplikacja może wydajnie odtwarzać wciągające filmy w wysokiej jakości. Pliki MV-HEVC mają strumień podstawowy, zwykle dla lewego oka, i strumień stereo dla drugiego oka.

Podobnie jak w przypadku filmu obok siebie możesz wczytać go za pomocą Media3 Exoplayera i wyrenderować za pomocą SurfaceEntity. Podczas wywoływania funkcji SurfaceEntity.create musisz określić, czy plik MV-HEVC jest głównym plikiem po lewej czy po prawej stronie, używając parametru 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()

Odtwarzanie filmów 180° i 360° za pomocą Jetpack SceneCore

SurfaceEntity obsługuje odtwarzanie filmów 180° na powierzchniach półkulistych i filmów 360° na powierzchniach sferycznych. Parametr radius domyślnie odnosi się do promienia odpowiednich powierzchni w metrach.

Poniższy kod pokazuje, jak skonfigurować SurfaceEntity do odtwarzania na półkuli 180° i sferze 360°. Podczas korzystania z tych kształtów płótna ustaw powierzchnię, wykorzystując pozycję głowy użytkownika, aby zapewnić wciągające wrażenia.

// 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.

Zaawansowane sterowanie elementem SurfaceEntity

Aby uzyskać bardziej zaawansowaną kontrolę nad renderowaniem filmów i obrazów, np. stosować niestandardowe efekty materiałów, możesz pracować bezpośrednio z SurfaceEntity z biblioteki SceneCore.

W sekcjach poniżej opisujemy niektóre zaawansowane funkcje dostępne na urządzeniu SurfaceEntity.

Zastosuj wtapianie krawędzi

Zmiękcz krawędzie powierzchni, aby lepiej dopasować ją do otoczenia, ustawiając właściwość 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)

Stosowanie maski alfa

Stosuj maski alfa, aby tworzyć powierzchnie inne niż prostokątne lub dodawać efekty przezroczystości. Najpierw wczytaj Texture z komponentu, a potem przypisz go do właściwości 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
}

Odtwarzanie filmów przestrzennych za pomocą Jetpack Compose na potrzeby XR

Jeśli chcesz dowiedzieć się, jak odtwarzać wideo za pomocą Jetpack Compose na potrzeby XR, dowiedz się, jak dodać powierzchnię dla treści obrazu lub wideo.