Создание и взаимодействие со сценой

Эта страница содержит общие советы по созданию Scene и взаимодействию с ней.

Рендеринг сцены без дополненной реальности

Класс SceneView позволяет визуализировать 3D-сцену, не требуя использования камеры устройства или сеанса дополненной реальности. Это полезно для предварительного просмотра 3D-объектов в приложении без дополненной реальности или предоставления альтернативных функций на устройствах, не поддерживающих дополненную реальность.

По умолчанию SceneView не отображает изображение с камеры дополненной реальности и использует черный фон. Чтобы изменить цвет фона, вы можете либо вызвать view.setBackgroundColor() , либо определить цвет фона в макете, как показано ниже:

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

Узел Camera сцены размещается в начале координат (позиция 0,0,0) и направлен вперед (направление 0,0,-1). Поскольку положение и вращение камеры не привязаны к отслеживанию движения AR, вы можете изменить положение или анимировать ее, как и любой другой узел.

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

Взаимодействия

Обработка касаний пользователя

Когда пользователь касается экрана, Sceneform передает событие касания обработчикам событий и слушателям, прикрепленным к узлам и сцене. Это поведение похоже на то, как события касания распространяются на представления и группы представлений в Android. Вот порядок распространения:

  1. Событие отправляется любому слушателю, добавленному в scene.addOnPeekTouchListener() .

    Это похоже на viewGroup.intercept() , за исключением того, что слушатель касания сцены не может использовать событие.

  2. Событие передается первому узлу, с которым пересекается луч.

    • Узел может использовать событие, определив набор методов onTouchEvent() , который возвращает true .
    • Если метод onTouchEvent() возвращает false или прослушиватель не определен, событие распространяется на родительский узел. Этот процесс продолжается до тех пор, пока событие не будет потреблено или не будет достигнута сцена.
  3. Наконец, если ни один слушатель не воспользовался событием, оно передается в scene.onTouchListener() .

Обнаружение жестов

ArFragment встроена поддержка жестов касания (выбора), перетаскивания (перемещения), сжатия (масштабирования) и скручивания (поворота).

Например, см. HelloSceneformActivity.java в примере приложения HelloSceneform .

Создание пользовательских узлов

Подобно созданию пользовательских представлений Android, вы можете создавать пользовательские узлы, создавая подклассы Node . Вот несколько ситуаций, когда вы можете захотеть создать пользовательский узел:

  • Вы хотите получить доступ к событиям жизненного цикла узла, таким как onUpdate() , onActivate и onDeactivate() .
  • Вы хотите создать узел, состоящий из группы узлов.
  • Вы дублируете много кода и можете выделить его в подкласс.

Например, см. Planet.java в примере приложения Solar System .

Анимация узлов

Существует два способа анимации узлов:

Анимация с помощью ObjectAnimator

Вот пример, который анимирует интенсивность прожектора:

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

Дополнительные сведения см. в разделе Анимация с помощью ObjectAnimator .

Анимация в onUpdate

Переопределите onUpdate() узла, чтобы анимировать его от кадра к кадру. В следующем примере из Planet.java в примерном приложении Солнечной системы информационная карточка настраивается в каждом кадре так, чтобы она смотрела на пользователя, даже когда планета вращается.

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

Добавить свет

Lights можно прикрепить к любому узлу сцены. По умолчанию каждая сцена Sceneform включает узел Sun , к которому подключен направленный свет.

Вы можете изменить солнце или добавить в сцену свои собственные источники света. В следующем примере добавляется прожектор:

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

Затем вызовите setLight() , чтобы прикрепить его к узлу.

Настроить визуализацию плоскости

По умолчанию у сцены есть PlaneRenderer , который выделяет Planes , когда они были обнаружены ARCore. Это выглядит так:

Вы можете изменить материал и текстуру по умолчанию, используемые для визуализации обнаруженных плоскостей. Вот как изменить текстуру:

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

Тени

Тени заставляют объекты рендеринга казаться привязанными к миру и дают пользователям ощущение глубины и пространства.

В Sceneform есть объекты, которые могут отбрасывать тени , и объекты, которые могут получать тени .

  • Lights и Renderables могут отбрасывать тени

    По умолчанию отбрасывание теней включено для солнца, но не для источников света. Вызовите setShadowCastingEnabled() , чтобы включить его.

  • Renderables и PlaneRenderer могут получать тени.

    По умолчанию прием теней включен. Вызовите setShadowReceiver() , чтобы отключить его.

Если визуализируемый объект одновременно отбрасывает и получает тени, он может отбрасывать тени на себя.