Tworzenie sceny i korzystanie z niej

Na tej stronie znajdziesz typowe wskazówki dotyczące tworzenia Scene i korzystania z niej.

Renderowanie sceny bez AR

Klasa SceneView umożliwia renderowanie sceny 3D bez konieczności korzystania z aparatu urządzenia ani sesji AR. Jest to przydatne, gdy chcesz wyświetlić podgląd obiektów 3D w aplikacji bez AR lub włączyć alternatywne funkcje na urządzeniach, które nie obsługują AR.

Domyślnie SceneView nie wyświetla obrazu z kamery AR i korzysta z czarnego tła. Aby zmienić kolor tła, możesz wywołać view.setBackgroundColor() lub zdefiniować kolor tła w układzie poniżej:

<com.google.ar.sceneform.SceneView
    android:id="@+id/scene_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/deep_teal"/>

Węzeł Camera sceny jest umieszczony w punkcie początkowym (pozycja 0,0,0) i kierowane do przodu (kierunek 0,0,-1). Pozycja i obrót kamery nie są powiązane ze śledzeniem ruchu w AR, dlatego możesz zmienić jej położenie lub animować ją jak każdy inny węzeł.

Camera camera = sceneView.getScene().getCamera();
camera.setLocalRotation(Quaternion.axisAngle(Vector3.right(), -30.0f));

Interakcje

Uchwyt do obsługi użytkownika

Gdy użytkownik dotyka ekranu, Sceneform rozdziela zdarzenie dotknięcia do modułów obsługi zdarzeń i detektorów podłączonych do węzłów oraz sceny. Działa to podobnie do sposobu, w jaki zdarzenia dotknięcia wpływają na widoki i grupy w Androidzie. Kolejność przenoszenia:

  1. Zdarzenie jest wysyłane do każdego detektora dodanego do grupy scene.addOnPeekTouchListener().

    Jest to podobny do elementu viewGroup.intercept(), z tą różnicą, że scena w odbiorniku niebawem odbiorcy nie może skorzystać ze zdarzenia.

  2. Zdarzenie jest przekazywane do pierwszego węzła, z którym łączy się promień.

    • Węzeł może przetwarzać zdarzenia, definiując zestaw metod onTouchEvent(), które zwraca true.
    • Jeśli metoda onTouchEvent() zwraca false lub nie określono żadnego detektora, zdarzenie jest propagowane do elementu nadrzędnego węzła. Proces ten trwa, dopóki wydarzenie nie zostanie wykorzystane lub nie zostanie osiągnięty punkt widokowy.
  3. Jeśli żaden detektor nie wykorzystał zdarzenia, jest ono przekazywane do scene.onTouchListener().

Wykrywanie gestów

ArFragment ma wbudowaną obsługę gestów dotykowych (przeciągania), przesuwania, ściągania i obrócenia.

Zobacz na przykład HelloSceneformActivity.java w przykładowej aplikacji HelloSceneform.

Tworzenie węzłów niestandardowych

Podobnie jak w przypadku tworzenia niestandardowych widoków Androida, możesz tworzyć węzły niestandardowe, klasyfikując je Node. Oto kilka sytuacji, w których warto utworzyć węzeł niestandardowy:

  • Chcesz uzyskać dostęp do zdarzeń w cyklu życia węzła, takich jak onUpdate(), onActivate i onDeactivate().
  • Chcesz utworzyć węzeł składający się z grupy węzłów.
  • Duplikujesz wiele kodów, więc możesz je dzielić na podklasę.

Przykład znajdziesz w artykule Planet.java w przykładowej aplikacji Układu Słonecznym.

Animowanie węzłów

Animacje węzłów są dostępne na 2 sposoby:

Animowanie za pomocą obiektu ObjectAnimator

Oto przykład intensywności animacji:

final int durationInMilliseconds = 1000;
final float minimumIntensity = 1000.0f;
final float maximumIntensity = 3000.0f;
ValueAnimator intensityAnimator =
    ObjectAnimator.ofFloat(
        spotlightNode.getLight(), "intensity", minimumIntensity, maximumIntensity);
intensityAnimator.setDuration(durationInMilliseconds);
intensityAnimator.setRepeatCount(ValueAnimator.INFINITE);
intensityAnimator.setRepeatMode(ValueAnimator.REVERSE);
intensityAnimator.start();

Więcej informacji znajdziesz w artykule Animowanie za pomocą obiektu Object Animator.

Animuj w OnUpdate

Zastąp węzeł onUpdate() węzła, aby ożywić go ramką. Poniższy przykład z przykładu (Planet.java) w przykładowej aplikacji Układ słoneczny dostosowuje każdą kartę informacyjną do twarzy użytkownika, nawet gdy planeta obraca się.

@Override
public void onUpdate(FrameTime frameTime) {
  Vector3 cameraPosition = getScene().getCamera().getWorldPosition();
  Vector3 cardPosition = infoCard.getWorldPosition();
  Vector3 direction = Vector3.subtract(cameraPosition, cardPosition);
  Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up());
  infoCard.setWorldRotation(lookRotation);
}

Dodaj światła

Lights można dołączyć do dowolnego węzła w scenie. Domyślnie każda scena zyskuje węzeł Sun z dołączonym oświetleniem kierunkowym.

Możesz zmienić oświetlenie słońca lub dodać własne oświetlenie. Ten przykład wyróżnia:

Light spotLightYellow =
    Light.builder(this, Light.Type.FOCUSED_SPOTLIGHT)
        .setColor(new Color(android.graphics.Color.YELLOW))
        .setShadowCastingEnabled(true)
        .build();

Następnie wywołaj setLight(), aby załączyć go do węzła.

Dostosowywanie wizualizacji samolotu

Domyślnie scena zawiera element PlaneRenderer z zaznaczeniem Planes, gdy został on wykryty przez ARCore. Wygląda on następująco:

Możesz zmienić domyślny materiał i teksturę używaną do renderowania wykrytych samolotów. Aby zmienić teksturę:

Texture.Sampler sampler =
        Texture.Sampler.builder()
                .setMinFilter(Texture.Sampler.MinFilter.LINEAR)
                .setWrapMode(Texture.Sampler.WrapMode.REPEAT)
                .build();

// R.drawable.custom_texture is a .png file in src/main/res/drawable
Texture.builder()
        .setSource(this, R.drawable.custom_texture)
        .setSampler(sampler)
        .build()
        .thenAccept(texture -> {
          arSceneView.getPlaneRenderer()
                  .getMaterial().thenAccept(material ->
                  material.setTexture(PlaneRenderer.MATERIAL_TEXTURE, texture));
        });

Cienie

Dzięki cieniom można wyrenderować ikony osadzone na świecie i dać użytkownikom poczucie głębi i przestrzeni.

W scenie są obiekty, które mogą przesyłać cienie, a w przypadku obiektów cienie.

  • Lights i Renderables mogą przesyłać cienie

    Domyślnie przesyłanie cienia jest włączone na słońcu, ale nie na świetle. Aby go włączyć, zadzwoń pod numer setShadowCastingEnabled().

  • Renderables i PlaneRenderer mogą otrzymywać cienie.

    Domyślnie włączone jest odbieranie cieni. Aby ją wyłączyć, zadzwoń pod numer setShadowReceiver().

Jeśli zarówno w trybie renderowanym, jak i całym występują cienie, sam może je przesyłać.