Crea una escena e interactúa con ella

Esta página contiene sugerencias comunes para compilar un Scene e interactuar con él.

Cómo renderizar una escena sin RA

La clase SceneView te permite renderizar una escena en 3D sin necesidad de usar la cámara del dispositivo ni de una sesión de RA. Esto es útil para obtener una vista previa de objetos 3D en tu app sin RA o proporcionar funcionalidades alternativas en dispositivos que no admiten RA.

De forma predeterminada, SceneView no muestra la imagen de la cámara de RA y usa un fondo negro. Para cambiar el color del fondo, puedes llamar a view.setBackgroundColor() o definir un color de fondo en el diseño, como se muestra a continuación:

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

El nodo Camera de la escena se ubica en el origen (posición 0,0,0) y hacia adelante (dirección 0,0-1). Debido a que la posición y la rotación de la cámara no están vinculadas al seguimiento de movimiento de RA, puedes cambiar su posición o animación como en cualquier otro nodo.

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

Interacciones

Cómo controlar la función táctil del usuario

Cuando el usuario toca la pantalla, Sceneform propaga el evento táctil a los controladores de eventos y los objetos de escucha adjuntos a los nodos y a la escena. Este comportamiento es similar al modo en que los eventos táctiles se propagan a las vistas y los grupos de vistas en Android. Este es el orden de propagación:

  1. El evento se envía a cualquier objeto de escucha que se agregue en scene.addOnPeekTouchListener().

    Esto es similar a viewGroup.intercept(), excepto que la escena en el objeto de escucha táctil no puede consumir el evento.

  2. El evento se pasa al primer nodo con el que el rayo se cruza.

    • El nodo puede consumir el evento mediante la definición de un conjunto de métodos onTouchEvent() que muestre true.
    • Si el método onTouchEvent() muestra false o no se define ningún objeto de escucha, el evento se propaga al elemento superior del nodo. Este proceso continúa hasta que se consume el evento o se alcanza la escena.
  3. Por último, si ningún objeto de escucha ha consumido el evento, este se pasa a scene.onTouchListener().

Cómo detectar gestos

ArFragment tiene compatibilidad integrada con gestos de presionar (seleccionar), arrastrar (mover), pellizcar (escalar) y girar (girar).

Por ejemplo, consulta HelloSceneformActivity.java en la app de muestra HelloSceneform.

Crear nodos personalizados

Al igual que con la creación de vistas personalizadas de Android, puedes crear nodos personalizados creando una subclase de Node. Estas son algunas situaciones en las que se recomienda crear un nodo personalizado:

  • Deseas acceder a eventos en el ciclo de vida del nodo, como onUpdate(), onActivate y onDeactivate().
  • Desea crear un nodo compuesto por un grupo de nodos.
  • Está duplicando mucho código y puede incluirlo en una subclase.

Para ver un ejemplo, consulta Planet.java en la app de ejemplo de Sistema solar.

Animar nodos

Hay dos maneras de animar nodos:

Cómo animar con ObjectAnimator

A continuación, te mostramos un ejemplo que anima la intensidad de un foco:

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 obtener más información, consulta Cómo animar con ObjectAnimator.

Animar en onUpdate

Anula el nodo onUpdate() del nodo para animarlo de fotograma a fotograma. En el siguiente ejemplo, de Planet.java en la app de ejemplo Sistema solar, se ajusta la tarjeta de información de cada fotograma para que apunte al usuario, incluso cuando el 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);
}

Agregar luces

Lights se puede adjuntar a cualquier nodo de la escena. De forma predeterminada, cada escena de Sceneform incluye un nodo Sun, que tiene una luz direccional adjunta.

Puedes modificar el sol o agregar tus propias luces a una escena. En el siguiente ejemplo, se agrega un Spotlight:

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

Luego, llama a setLight() para adjuntarla a un nodo.

Cómo personalizar la visualización del plano

De forma predeterminada, la escena tiene un elemento PlaneRenderer que destaca Planes cuando ARCore los detecta. El aspecto resultante será el siguiente:

Puedes modificar el material y la textura predeterminados que se usan para renderizar los planos detectados. Para cambiar la textura, sigue estos pasos:

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

Las sombras hacen que los elementos renderizados parezcan basados en el mundo y ofrecen a los usuarios una sensación de profundidad y espacio.

En Sceneform, hay objetos que pueden lanzar sombras y objetos que pueden recibir sombras.

  • Lights y Renderables pueden proyectar sombras

    De manera predeterminada, la proyección de sombras está habilitada en el sol, pero no para las luces. Llama a setShadowCastingEnabled() para activarla.

  • Renderables y PlaneRenderer pueden recibir sombras.

    De forma predeterminada, la recepción de sombras está habilitada. Llama a setShadowReceiver() para desactivarla.

Si un renderizado se proyecta y recibe sombras, puede proyectar sombras sobre sí mismo.