Criar e interagir com uma cena

Esta página contém dicas comuns para criar uma Scene e interagir com ela.

Renderizar uma cena sem RA

A classe SceneView permite renderizar uma cena 3D sem exigir o uso da câmera do dispositivo nem de uma sessão de RA. Isso é útil para visualizar objetos 3D no seu app sem RA ou para oferecer funcionalidades alternativas em dispositivos incompatíveis com RA.

Por padrão, SceneView não exibe a imagem da câmera de RA e usa um plano de fundo preto. Para mudar a cor de fundo, você pode chamar view.setBackgroundColor() ou definir uma cor de plano de fundo no layout, conforme mostrado abaixo:

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

O nó Camera da cena é posicionado na origem (posição 0,0,0) e voltado para frente (direção 0,0,-1). Como a posição e a rotação da câmera não estão vinculadas ao rastreamento de movimento de RA, você pode reposicionar ou animar esse elemento como qualquer outro nó.

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

Interações

Gerenciar o toque do usuário

Quando o usuário toca na tela, o Sceneform propaga o evento de toque para os manipuladores de eventos e listeners anexados aos nós e à cena. Esse comportamento é semelhante à forma como os eventos de toque se propagam para visualizações e grupos de visualização no Android. Esta é a ordem da propagação:

  1. O evento é enviado para qualquer listener adicionado ao scene.addOnPeekTouchListener().

    Isso é semelhante a viewGroup.intercept(), exceto pelo fato de que a cena do listener de toque de visualização não pode consumir o evento.

  2. O evento é transmitido para o primeiro nó em que o raio se cruza.

    • O nó pode consumir o evento definindo um conjunto de métodos onTouchEvent() que retorna true.
    • Se o método onTouchEvent() retornar false ou se nenhum listener estiver definido, o evento será propagado para o pai do nó. Esse processo continua até que o evento seja consumido ou a cena seja alcançada.
  3. Por fim, se nenhum listener tiver consumido o evento, ele será transmitido para scene.onTouchListener().

Detectar gestos

O ArFragment tem suporte integrado para gestos de toque (seleção), arrastar (mover), fazer gesto de pinça (escala) e torcer (girar).

Por exemplo, veja HelloSceneformActivity.java no app de exemplo HelloSceneform.

Criar nós personalizados

Assim como na criação de visualizações personalizadas do Android, é possível criar nós personalizados gerando subclasses de Node. Veja algumas situações em que talvez você queira criar um nó personalizado:

  • Você quer acessar eventos no ciclo de vida do nó, como onUpdate(), onActivate e onDeactivate().
  • Você quer criar um nó composto por um grupo de nós.
  • Você está duplicando muito código e pode fatorá-lo em uma subclasse.

Para ver um exemplo, consulte Planet.java no app de exemplo do sistema Solar (em inglês).

Animar nós

Há duas maneiras de animar nós:

Animar com o ObjectAnimator

Veja um exemplo que anima a intensidade do destaque:

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

Para ver mais informações, consulte Animar com o ObjectAnimator.

Animar em onUpdate

Substitua o onUpdate() do nó para animá-lo frame a frame. O exemplo a seguir, do Planet.java no app de exemplo Sistema Solar (link em inglês), ajusta o card de informação a cada frame para o usuário, mesmo quando o planeta gira.

@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);
}

Adicionar luzes

Lights pode ser anexado a qualquer nó no cenário. Por padrão, cada cena do Sceneform inclui um nó Sun, que tem uma luz direcional anexada.

Você pode modificar o sol ou adicionar suas luzes a uma cena. O exemplo a seguir adiciona um destaque:

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

Em seguida, chame setLight() para anexar a um nó.

Personalizar a visualização do plano

Por padrão, a cena tem um PlaneRenderer que destaca Planes quando eles são detectados pelo ARCore. Ela é assim:

É possível modificar o material e a textura padrão usados para renderizar os planos detectados. Veja como alterar a textura:

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));
        });

Sombras

As sombras fazem com que os renderable pareçam aterrissados no mundo e dão aos usuários uma sensação de profundidade e espaço.

No Sceneform, há objetos que podem mostrar sombras e objetos que podem receber sombras.

Se um elemento renderizável gera e recebe sombras, ele pode lançar sombras em si mesmo.