Нвоости

Разработайте свое приложение виртуальной реальности с помощью Google VR (практическое задание) — IT News

Чтобы создавать возможности виртуальной реальности в наших приложениях, Google предоставила разработчикам платформу Google VR.

В последнее время мы были погружены в обработку изображений, но в этом посте, и чтобы немного изменить тему в скобках, мы познакомимся с виртуальной реальностью. Благодаря доступным очкам, таким как CardBoard, самым мощным, таким как Oculus или HTC Vive, или промежуточным, но интересным PlayStationVR, в 2016 году распространение виртуальной реальности было огромным. Но не волнуйтесь, благодаря Google VR мы не останемся позади.

Виртуальная реальность Google CardBoard

Чтобы создавать реалистичные впечатления в наших приложениях, Google предоставила разработчикам доступ к платформе Google VR. Эта платформа предоставляет все необходимое для разработки приложений, включая библиотеки, примеры, рекомендации и т. д. Все это доступно благодаря следующим API:

  • Единство: API, который позволяет добавить поддержку виртуальной реальности в приложение Unity3D или создать его с нуля.
  • Андроид: позволяет создавать приложения, отображающие 3D-фото и видео, пространственный звук, обнаруживающие движения головы и т. д.
  • iOS: позволяет создавать виртуальную реальность с помощью Objective-C.
  • Нереальный движок: изначально поддерживает Google VR для виртуальной реальности в мобильных приложениях.

Для каждого API у нас есть документация и примеры, которые мы можем использовать для ознакомления с этой технологией. Мы, как и во всех предыдущих постах, сосредоточимся на Android-версиях.

В этом случае API облегчит разработчику следующие действия:

  • Коррекция дисторсии объектива.
  • пространственное аудио.
  • Отслеживание головы.
  • 3D калибровка.
  • Параллельный просмотр.
  • Настройка стереогеометрии.
  • Обработка пользовательских событий.

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

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

Загрузите содержимое для отображения

Первое, что нам нужно сделать, это получить допустимый контент для отображения. Чтобы не использовать пример, предоставленный Google, лучше всего использовать один из наших. Создание панорамных или 360 фотографий может быть трудным (в основном для получения качественных изображений), поэтому мы воспользуемся преимуществами изображений Google Street View.

Благодаря streetviewdownload.eu мы можем скачать любое изображение, снятое Google, и очень просто использовать его в нашем приложении. Вы можете увидеть шаги, чтобы следовать в этом видео.

В нашем случае мы загрузили изображение рядом с базовым лагерем Эвереста.

Крупный план базового лагеря Эвереста

Игра с кодом

  1. Создаем новое приложение с шаблоном «Пустой активности» и устанавливаем минимальный SDK 25 (это обязательно).
  2. Убеждаемся, что jcenter находится в gradle проекта.
    allprojects {
        repositories {
            jcenter()
        }
    }
    
  3. В градле приложения, в разделе зависимостей, добавляем следующее и синхронизируем:
    compile 'com.google.vr:sdk-panowidget:1.70.0'
  4. Пришло время добавить jpg, который мы хотим показать в проекте. В дереве проекта щелкните правой кнопкой мыши приложение, выберите New/Folder/Assets Folder и скопируйте файл. В нашем случае это everest.jpg.
  5. В макете активности мы очищаем основной макет и добавляем следующее представление:
    <com.google.vr.sdk.widgets.pano.VrPanoramaView
        android:id="@+id/pano_view"
        android:layout_margin="5dip"
        android:layout_width="match_parent"
        android:scrollbars="@null"
        android:layout_height="250dip"/>
    

    Этот вид находится в библиотеке, добавленной на шаге 3, и представляет собой средство просмотра изображений на 360 градусов.

  6. Мы открываем MainActivity и добавляем переменные, которые будем использовать:
    private static final String TAG = MainActivity.class.getSimpleName();
    private VrPanoramaView panoWidgetView;
    public boolean loadImageSuccessful;
    private Uri fileUri;
    private Options panoOptions = new Options();
    private ImageLoaderTask backgroundImageLoaderTask;
    

    Мы будем использовать тег в логах.
    У нас будет переменная вида панорамы макета, логическое значение, чтобы узнать, правильно ли загружено изображение, Uri для загрузки файла, параметры для установки характеристик панорамы и поток для загрузки изображения в параллельно, избегая блокировки основного потока.

  7. В методе onCreate мы добавляем этот код:
    panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);
    panoWidgetView.setEventListener(new ActivityEventListener());
    
    handleIntent(getIntent());
    

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

  8. Добавляем метод handleIntent
    private void handleIntent(Intent intent) {
        if (Intent.ACTION_VIEW.equals(intent.getAction())) {
            Log.i(TAG, "ACTION_VIEW Intent recieved");
    
            fileUri = intent.getData();
            if (fileUri == null) {
                Log.w(TAG, "No data uri specified. Use "-d /path/filename".");
            } else {
                Log.i(TAG, "Using file " + fileUri.toString());
            }
    
            panoOptions.inputType = intent.getIntExtra("inputType", Options.TYPE_MONO);
            Log.i(TAG, "Options.inputType = " + panoOptions.inputType);
        } else {
            Log.i(TAG, "Intent is not ACTION_VIEW. Using default pano image.");
            fileUri = null;
            panoOptions.inputType = Options.TYPE_MONO;
        }
    
        if (backgroundImageLoaderTask != null) {
            backgroundImageLoaderTask.cancel(true);
        }
        backgroundImageLoaderTask = new ImageLoaderTask();
        backgroundImageLoaderTask.execute(Pair.create(fileUri, panoOptions));
    }

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

  9. Мы добавляем методы, которые хотим переопределить.
    @Override
    protected void onNewIntent(Intent intent) {
        Log.i(TAG, this.hashCode() + ".onNewIntent()");
        setIntent(intent);
        handleIntent(intent);
    }
    @Override
    protected void onPause() {
        panoWidgetView.pauseRendering();
        super.onPause();
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        panoWidgetView.resumeRendering();
    }
    
    @Override
    protected void onDestroy() {
        panoWidgetView.shutdown();
    
        if (backgroundImageLoaderTask != null) {
            backgroundImageLoaderTask.cancel(true);
        }
        super.onDestroy();
    }

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

  10. Добавляем поток, который будет отвечать за загрузку изображения:
    class ImageLoaderTask extends AsyncTask<Pair<Uri, Options>, Void, Boolean> {
    
        @Override
        protected Boolean doInBackground(Pair<Uri, Options>... fileInformation) {
            Options panoOptions = null;  // It's safe to use null VrPanoramaView.Options.
            InputStream istr = null;
            if (fileInformation == null || fileInformation.length < 1
                    || fileInformation[0] == null || fileInformation[0].first == null) {
                AssetManager assetManager = getAssets();
                try {
                    istr = assetManager.open("everest.jpg");
                    panoOptions = new Options();
                    panoOptions.inputType = Options.TYPE_MONO;
                } catch (IOException e) {
                    Log.e(TAG, "Could not decode default bitmap: " + e);
                    return false;
                }
            } else {
                try {
                    istr = new FileInputStream(new File(fileInformation[0].first.getPath()));
                    panoOptions = fileInformation[0].second;
                } catch (IOException e) {
                    Log.e(TAG, "Could not load file: " + e);
                    return false;
                }
            }
    
            panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions);
            try {
                istr.close();
            } catch (IOException e) {
                Log.e(TAG, "Could not close input stream: " + e);
            }
    
            return true;
        }
    }

    Загрузите изображение из файла и дождитесь его загрузки в панораму.

  11. Чтобы закончить, мы должны добавить класс слушателя панорамы. Мы будем использовать его, чтобы узнать, правильно ли загружено изображение.
    private class ActivityEventListener extends VrPanoramaEventListener {
       @Override
        public void onLoadSuccess() {
            loadImageSuccessful = true;
        }
    
       @Override
        public void onLoadError(String errorMessage) {
            loadImageSuccessful = false;
            Toast.makeText(
                    MainActivity.this, "Error loading pano: " + errorMessage, Toast.LENGTH_LONG)
                    .show();
            Log.e(TAG, "Error loading pano: " + errorMessage);
        }
    }
  12. Бегаем и наслаждаемся 3D изображением.

Видео о базовом лагере Эвереста

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

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

В будущих постах мы увидим больше возможностей, которые предлагает нам Google VR. А пока продолжайте программировать!

Вы можете скачать код этого примера.