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:
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.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 zwracatrue
. - Jeśli metoda
onTouchEvent()
zwracafalse
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.
- Węzeł może przetwarzać zdarzenia, definiując zestaw metod
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
ionDeactivate()
. - 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:
- Użyj interfejsu
ObjectAnimator
ze standardowego interfejsu API animacji Android. - Utwórz klasę węzła niestandardowego i zastąp
onUpdate()
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
iRenderables
mogą przesyłać cienieDomyślnie przesyłanie cienia jest włączone na słońcu, ale nie na świetle. Aby go włączyć, zadzwoń pod numer
setShadowCastingEnabled()
.Renderables
iPlaneRenderer
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ć.