Как сделать дополненную реальность

Vuforia

Являясь полноценной SDK для разработчиков, Vuforia представляет собой набор инструментов для создания приложений дополненной реальности.

Vuforia поддерживает:

  • распознавание нескольких целей одновременно (включая объекты, изображения и текст);
  • отслеживание целей;
  • распознавание 2D и 3D форматов;
  • сканирование реального объекта для последующего распознавания;
  • виртуальные кнопки;
  • отображение дополнительных элементов через OpenGL;
  • Smart TerrainTM – возможность реконструировать окружающий ландшафт, создавая его 3D-карту;
  • Extended Tracking – возможность продлить отображение цели на мобильном устройстве, даже когда она находится вне поля зрения.

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

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

Однако отсутствие полноценного руководства по использованию библиотеки затрудняет первый опыт работы с Vuforia. Отдельные инструкции и краткие советы представлены в большом количестве, но не упорядочены и поэтому не заменяют разработчику необходимую документацию.

В бесплатном варианте библиотеки есть ограничения по использованию cloud recognition, а также один раз в день использования появляется водный знак компании.

ARToolKit

ARToolKit представляет собой набор программных библиотек, которые могут использоваться в AR приложениях. Главное достоинство библиотеки – открытый исходный код. То есть библиотека распространяется абсолютно бесплатно.

К основным возможностям ARToolKit относятся:

  • распознавание 2D формата;
  • отображение дополнений через OpenGL.

Библиотека предназначена для отслеживания в кадре камеры мобильного устройства заранее известных квадратных маркеров объектов и воспроизведения на экране их расположения в пространстве. С помощью этих данных создается интерфейс дополненной реальности.

ARToolKit подходит для работы на разных платформах: Android, iOS, Windows, Linux, Mac OS X, SGI. Для каждой конкретной операционной системы нужна своя среда разработки. Бесплатные среды доступны на всех платформах.

Несмотря на бесплатный доступ к библиотеке, документация для разработчиков весьма ограничена. Есть тестовые приложения, но не все из них удается собрать. Код примеров представлен плохо и нет информации по дальнейшему развитию библиотеки.

Wikitude

Библиотека Wikitude поддерживает:

  • распознавание 2D и 3D форматов (изображения, текст, видео);
  • возможность сканирования реального объекта для последующего распознавания;
  • рендеринг и анимацию 3D-моделей;
  • отслеживание местоположения объектов;
  • возможность HTML аугментации.

Задействуя Wikitude, можно создавать приложения для отображения мест вокруг пользователя на виртуальной карте или в виде списка, для поисковых запросов о событиях, твитах, статьях из Википедии, для получения рекомендаций от других пользователей. Кроме этого, приложение на базе WikiTude позволит получать мобильные купоны, информацию о выгодных предложениях и скидках в магазинах вокруг, а также играть в AR-игры.

Wikitude может использоваться для платформ Android, iOS, как плагин для PhoneGap, модульный элемент для Titanium и компонента для Xamarin. Этот фреймворк подходит для умных очков Google Glass, Epson Moverio, Vuzix M-100 и ODG R-7. Включает в себя SLAM и поддерживает Unity.

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

Kudan AR

Функционал библиотеки Kudan включает в себя:

  • распознавание изображений;
  • отображение дополнений на основе положения пользователя и распознанных изображений;
  • безмаркерное отслеживание объектов (без реперных точек, только на основе реальных характеристик объекта – углов, изгибов или текстур);
  • отображение дополнений через отдельный компонент-обертку над OpenGL.

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

Разработчики могут воспользоваться базовой документацией при обращении к библиотеке, однако руководство по использованию не слишком подробное и требует поиска дополнительной информации. Также есть риск, что при создании приложения может не хватить встроенных возможностей библиотеки, а доступ напрямую к OpenGL отсутствует.

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

Тем не менее, остановившись перед выбором конкретного фреймворка, разработчику важно понимать, что он получит в своё распоряжение. Часть инструментов можно использовать бесплатно, просто зайдя на сайт или скачав небольшую программу. Другие требуют заключения партнерских отношений и регулярной платы, но при этом обеспечивают более развернутый и качественный функционал. Делая выбор в пользу определенной AR-библиотеки, прежде всего отталкивайтесь от задач своего проекта, от планируемых результатов, и соизмеряйте их с возможностями выбранных решений.

Начало работы с приложением дополненной реальности

Теперь, когда вы ознакомились с ARCore и выбрали хорошее изображение с оценкой 75+, пришло время приступить к написанию кода приложения.

Создание фрагмента

Мы создадим фрагмент и добавим его в нашу Activity. Создаём класс с именем CustomArFragment и наследуем его от ArFragment. Вот код для CustomArFragment:

package com.ayusch.augmentedimages; import android.util.Log; import com.google.ar.core.Config; import com.google.ar.core.Session; import com.google.ar.sceneform.ux.ArFragment; public class CustomArFragment extends ArFragment { @Override protected Config getSessionConfiguration(Session session) { getPlaneDiscoveryController().setInstructionView(null); Config config = new Config(session); config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE); session.configure(config); getArSceneView().setupSession(session); return config; } }

Прежде всего, мы отключаем обнаружение плоскости. Делая это, мы убираем с экрана значок руки, который появляется сразу после инициализации фрагмента и говорит пользователю о необходимости перемещения своего смартфона для поиска плоскости. Нам это больше не нужно, поскольку мы обнаруживаем не случайные плоскости, а конкретное изображение.

Затем мы устанавливаем режим обновления для сессии LATEST_CAMERA_IMAGE. Это гарантирует, что мы будем узнавать об обновлениях изображения всякий раз, когда обновится кадр камеры.

Настройка базы данных изображений

Добавьте выбранное опорное изображение (которое вы хотите обнаружить в физическом мире) в папку assets (создайте её, если её ещё нет). Теперь мы можем добавлять изображения в нашу базу данных.

Мы создадим эту базу данных, как только будет создан фрагмент. В логи мы выведем результат этой операции:

if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) { Log.d(«SetupAugImgDb», «Success»); } else { Log.e(«SetupAugImgDb»,»Faliure setting up db»); }

Вот как будет выглядеть CustomArFragment:

package com.ayusch.augmentedimages; import android.util.Log; import com.google.ar.core.Config; import com.google.ar.core.Session; import com.google.ar.sceneform.ux.ArFragment; public class CustomArFragment extends ArFragment { @Override protected Config getSessionConfiguration(Session session) { getPlaneDiscoveryController().setInstructionView(null); Config config = new Config(session); config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE); session.configure(config); getArSceneView().setupSession(session); if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) { Log.d(«SetupAugImgDb», «Success»); } else { Log.e(«SetupAugImgDb»,»Faliure setting up db»); } return config; } }

Вскоре мы добавим метод setupAugmentedImagesDb в MainActivity. Теперь давайте добавим CustomArFragment в наш activity_main.xml:

<?xml version=»1.0″ encoding=»utf-8″?> <android.support.constraint.ConstraintLayout xmlns:android=»http://schemas.android.com/apk/res/android» xmlns:app=»http://schemas.android.com/apk/res-auto» xmlns:tools=»http://schemas.android.com/tools» android:layout_width=»match_parent» android:layout_height=»match_parent» tools:context=».MainActivity»> <fragment android:id=»@+id/sceneform_fragment» android:name=»com.ayusch.augmentedimages.CustomArFragment» android:layout_width=»match_parent» android:layout_height=»match_parent» /> </android.support.constraint.ConstraintLayout>

Добавление изображения в базу данных

Сейчас мы настроим нашу базу данных изображений, обнаружим опорное изображение в реальном мире и добавим 3D-модель на изображение.

Давайте начнём с настройки нашей базы данных. Создайте публичный метод setupAugmentedImagesDb в классе MainActivity:

public boolean setupAugmentedImagesDb(Config config, Session session) { AugmentedImageDatabase augmentedImageDatabase; Bitmap bitmap = loadAugmentedImage(); if (bitmap == null) { return false; } augmentedImageDatabase = new AugmentedImageDatabase(session); augmentedImageDatabase.addImage(«tiger», bitmap); config.setAugmentedImageDatabase(augmentedImageDatabase); return true; } private Bitmap loadAugmentedImage() { try (InputStream is = getAssets().open(«blanket.jpeg»)) { return BitmapFactory.decodeStream(is); } catch (IOException e) { Log.e(«ImageLoad», «IO Exception», e); } return null; }

Мы также создали метод loadAugmentedImage, который загружает изображение из папки ресурсов и возвращает растровое изображение.

В setupAugmentedImagesDb мы сначала инициализируем нашу базу данных для текущей сессии, а затем добавляем изображение в эту базу данных. Мы назвали наше изображение tiger. Затем мы устанавливаем эту базу данных в конфиг и возвращаем true, сообщая о том, что изображение успешно добавлено.

Обнаружение опорных изображений в реальном мире

Теперь мы начнем обнаруживать наши опорные изображения в реальном мире. Для этого мы создадим слушателя, который будет вызываться каждый раз при обновлении видеокадра, и этот кадр будет проанализирован на предмет наличия там опорного изображения.

Добавьте эту строку в метод onCreate() в MainActivity:

arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);

Теперь добавьте метод onUpdateFrame в MainActivity:

@RequiresApi(api = Build.VERSION_CODES.N) private void onUpdateFrame(FrameTime frameTime) { Frame frame = arFragment.getArSceneView().getArFrame(); Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class); for (AugmentedImage augmentedImage : augmentedImages) { if (augmentedImage.getTrackingState() == TrackingState.TRACKING) { if (augmentedImage.getName().equals(«tiger») && shouldAddModel) { placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse(«Mesh_BengalTiger.sfb»)); shouldAddModel = false; } } } }

В первой строке мы получаем сам кадр. Кадр можно представить, как обычный скриншот из видео. Если вы знакомы с тем, как работает видео, вы знаете, что это просто набор изображений, которые очень быстро сменяют друг друга, создавая впечатление чего-то движущегося. Мы просто берём одну из этих картинок.

После того, как мы получили кадр, мы анализируем его на предмет наличия на нём нашего опорного изображения. Мы берём список всех элементов, отслеженных ARCore, используя frame.getUpdatedTrackables. Затем мы перебираем её и проверяем, присутствует ли в кадре наше изображение tiger.

Если совпадение найдено, то мы просто берём и размещаем 3D-модель поверх обнаруженного изображения.

Примечание. Флаг shouldAddModel используется для того, чтобы мы добавляли 3D-модель только один раз.

Размещение 3D-модели над опорным изображением

Теперь, когда мы нашли наше опорное изображение в реальном мире, мы можем добавлять 3D-модель поверх него. Добавим методы placeObject и addNodeToScene:

  • placeObject: этот метод используется для построения отрендеренного объекта по заданному Uri. Как только рендеринг завершён, объект передаётся в метод addNodeToScene, где объект прикрепляется к узлу, и этот узел помещается на сцену.
  • addNodeToScene: этот метод создаёт узел из полученного якоря, создаёт другой узел, к которому присоединяется визуализируемый объект, затем добавляет этот узел в якорный узел и помещает его на сцену.

Вот так теперь выглядит MainActivity:

package com.ayusch.augmentedimages; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.support.annotation.RequiresApi; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import com.google.ar.core.Anchor; import com.google.ar.core.AugmentedImage; import com.google.ar.core.AugmentedImageDatabase; import com.google.ar.core.Config; import com.google.ar.core.Frame; import com.google.ar.core.Session; import com.google.ar.core.TrackingState; import com.google.ar.sceneform.AnchorNode; import com.google.ar.sceneform.FrameTime; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.rendering.Renderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.TransformableNode; import java.io.IOException; import java.io.InputStream; import java.util.Collection; public class MainActivity extends AppCompatActivity { ArFragment arFragment; boolean shouldAddModel = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); arFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_fragment); arFragment.getPlaneDiscoveryController().hide(); arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame); } @RequiresApi(api = Build.VERSION_CODES.N) private void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) { ModelRenderable.builder() .setSource(arFragment.getContext(), uri) .build() .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable)) .exceptionally(throwable -> { Toast.makeText(arFragment.getContext(), «Error:» + throwable.getMessage(), Toast.LENGTH_LONG).show(); return null; } ); } @RequiresApi(api = Build.VERSION_CODES.N) private void onUpdateFrame(FrameTime frameTime) { Frame frame = arFragment.getArSceneView().getArFrame(); Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class); for (AugmentedImage augmentedImage : augmentedImages) { if (augmentedImage.getTrackingState() == TrackingState.TRACKING) { if (augmentedImage.getName().equals(«tiger») && shouldAddModel) { placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse(«Mesh_BengalTiger.sfb»)); shouldAddModel = false; } } } } public boolean setupAugmentedImagesDb(Config config, Session session) { AugmentedImageDatabase augmentedImageDatabase; Bitmap bitmap = loadAugmentedImage(); if (bitmap == null) { return false; } augmentedImageDatabase = new AugmentedImageDatabase(session); augmentedImageDatabase.addImage(«tiger», bitmap); config.setAugmentedImageDatabase(augmentedImageDatabase); return true; } private Bitmap loadAugmentedImage() { try (InputStream is = getAssets().open(«blanket.jpeg»)) { return BitmapFactory.decodeStream(is); } catch (IOException e) { Log.e(«ImageLoad», «IO Exception», e); } return null; } private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) { AnchorNode anchorNode = new AnchorNode(anchor); TransformableNode node = new TransformableNode(arFragment.getTransformationSystem()); node.setRenderable(renderable); node.setParent(anchorNode); arFragment.getArSceneView().getScene().addChild(anchorNode); node.select(); } }

Теперь запустите ваше приложение. Вы должны увидеть экран, как показано ниже. Подвигайте телефон немного над опорным объектом. И как только ARCore обнаружит опорное изображение в реальном мире, добавит на него вашу 3D-модель.

Читайте также: Создание вашего первого ARCore-приложения