Доповнена реальність зі Swift 5 - з чого почати

Доповнена реальність зі Swift 5 - з чого почати

Уявіть, що межа між віртуальним і реальним світом зникла.

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

Популярні додатки Apple AR

Measure

З iOS 12 ви можете залишити рулетку в кухонній шухляді. Після встановлення iOS 12 ви побачите один з нових додатків доповненої реальності від Apple під назвою Measure. Додаток використовує доповнену реальність як лінійку, вимірюючи об'єкти навколо вас за допомогою камери телефону.

Just a Line

Just a Line дозволяє створювати прості малюнки в доповненій реальності, а потім ділитися своїми творіннями у вигляді короткого відео. Малюйте наодинці або з другом, а потім натисніть "записати" і поділіться тим, що ви зробили, за допомогою #justaline.

Knightfall: AR

Knightfall AR - це досвід доповненої реальності, який переносить нас у світ Лицарів Храму, які захищають місто Акко від загарбницької армії та охороняють найціннішу реліквію християнства - Святий Грааль. Використовуйте свою кмітливість і гостре око, щоб вбити якомога більше ворожих воїнів, перш ніж вони прорвуться крізь стіни.

Системні вимоги

Apple принесла доповнену реальність у маси, починаючи з iOS 11. З моменту запуску iOS 11 сотні мільйонів iPhone та iPad підтримують AR. Це одразу робить Apple ARKit найбільшою AR-платформою у світі.

Якщо вас цікавить розробка AR-додатків для iOS, ви потрапили в правильне місце.

ARKit 2

ARKit 2 для розробників iOS - це платформа, яку Apple представила разом з iOS 12. Розробники можуть створювати взаємопов'язані простори доповненої реальності та постійні об'єкти, прив'язані до певних місць, а також використовувати ідентифікацію об'єктів та автоматичне відстеження зображень. Для створення нашого демонстраційного проекту ми будемо використовувати ARKit 2.

Налаштування проекту

Створення нового проекту

Для початку відкрийте Xcode і виберіть у меню "Файл" > "Створити" > "Проект". Виберіть "Single View App" і натисніть "Далі". Xcode має зразок ARKit, але для кращого розуміння ми використаємо зразок "Single View App" для створення нашого нового додатку доповненої реальності.

Дозвіл на використання камери

Тепер перед запуском нашого AR-додатку нам потрібно повідомити користувачеві, що ми будемо використовувати камеру його пристрою для доповненої реальності. Ця вимога з'явилася з моменту запуску iOS 10. Для цього відкрийте Info.plist, клацніть правою кнопкою миші на порожньому місці і виберіть "Додати рядок", потім встановіть ключ "Конфіденційність - Опис використання камери" і на завершення додайте опис того, навіщо вам потрібно використовувати камеру.

Додавання ARKit SceneKit View до розкадровки

Відкрийте Main.storyboard і виберіть ARKit SceneKit View з бібліотеки

Перетягніть його на головний контролер і закріпіть з боків.

Потім, натиснувши і утримуючи праву кнопку на ARKit SceneKit View, ми зв'язуємо його з контролером. Після додавання @IBOutlet ми побачимо помилку "Use of undeclared type ARSCNView", це відбувається, тому що ми не імпортували ARKit.

Просто додавши імпорт ARKit до нашого контролера, ми виправимо це.

Налаштування сеансу ARSCNView

Ми хочемо, щоб наш додаток подивився на світ через камеру і почав розпізнавати навколишнє середовище. Apple зробила доповнену реальність доступною для розробників без необхідності створювати всю технологію з нуля. Дякую, Apple!

Чудово. Настав час налаштувати ARKit SceneKit View. Заповніть наступний код у класі ViewController:

 private let configuration = ARWorldTrackingConfiguration()
 
 override func viewDidLoad() {
        super.viewDidLoad()
        // Show statistics such as fps and timing information
        self.sceneView.showsStatistics = true
        self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
    }
 
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.sceneView.session.run(configuration)
    }
 
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.sceneView.session.pause()
    }

Перший рядок - це конфігурація відстеження зовнішнього світу. Але зупиніться, що це? "Конфігурація відстеження світу" відстежує орієнтацію і положення пристрою. Вона також визначає реальні поверхні, видимі через камеру.

Для налагодження viewDidLoad ми встановили sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]. Це дозволить побачити, як ARKit виявляє поверхню. Коли ми запускаємо програму, то бачимо багато жовтих плям на поверхні. Ці плями дозволяють оцінити такі властивості, як орієнтація та положення фізичних об'єктів у поточному базовому середовищі. Чим більше плям ми бачимо, тим більше шансів, що ARKit зможе розпізнати і відстежити оточення.

Далі, щоб запустити сцену до того, як з'явиться екран, ми запустимо сеанс нашої сцени у viewWillAppear з нашою конфігурацією. Перед тим, як екран у viewWillDisappear зникне, ми поставимо його на паузу. Запускаємо додаток і дивимося, що у нас вийшло:

Ми бачимо статистику в нижній частині екрану, її можна зробити більш детальною, натиснувши на +. Також ми бачимо жовті плями, вони вказують на місця, де виявлено об'єкти.

AR осі

Вісь X часто використовується для позиціонування об'єкта в світі, праворуч або ліворуч. Вісь Y використовується для позиціонування об'єктів у верхній або нижній частині, а вісь Z використовується для визначення того, наскільки близько об'єкт знаходиться до джерела.

Позитивне значення X переміщує об'єкт праворуч, а негативне - ліворуч. Позитивне значення Y помістить об'єкт у верхній частині, а негативне - в нижній, позитивне значення Z наблизить об'єкт до користувача, а негативне - віддалить.

Додавання віртуального об'єкта

Тепер давайте додамо код для додавання віртуального об'єкта до нашого проекту.

private var node: SCNNode!
 
func addBox(x: Float = 0, y: Float = 0, z: Float = -0.2) {
        // 1
        let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
 
        // 2
        let colors = [UIColor.green, // front
            UIColor.red, // right
            UIColor.blue, // back
            UIColor.yellow, // left
            UIColor.purple, // top
            UIColor.gray] // bottom
        let sideMaterials = colors.map { color -> SCNMaterial in
            let material = SCNMaterial()
            material.diffuse.contents = color
            material.locksAmbientWithDiffuse = true
            return material
        }
        box.materials = sideMaterials
 
        // 3
        self.node = SCNNode()
        self.node.geometry = box
        self.node.position = SCNVector3(x, y, z)
 
        //4
        sceneView.scene.rootNode.addChildNode(self.node)
    }

Давайте розглянемо цей код більш детально:

  1. Створюємо тут віртуальний об'єкт у вигляді куба з гранню 0,1 метра. 1 поплавок = 1 метр.
  2. Ми додаємо різні кольори до кожної грані та створюємо масив кольорів, потім ми створюємо матеріал SCNMaterial для кожної грані на карті та призначаємо отриманий масив матеріалам нашого куба.
  3. Ми створюємо об’єкт SCNNode, він представляє положення та координати об’єкта в тривимірному просторі. Сам вузол не містить візуального вмісту. Додаємо до нього наш куб.
  4. Нарешті, ми додаємо наш вузол до сцени.

Позиціонування та переміщення віртуального об'єкта

Настав час додати наш куб до реального світу. Спробуємо зробити так, щоб кубик додавався на екран в тому місці, де ми натискаємо.

По-перше, ми повинні додати функцію від’єднання клацання на нашій сцені та викликати її у iewDidLoad().

private func addTapGesture() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
        self.sceneView.addGestureRecognizer(tapGesture)
    }

Потім ми додамо код, який знайде поверхню, куди помістити наш куб після клацання, і додасть куб на сцену, якщо його ще немає, або перемістить його, якщо він уже там.

  @objc func didTap(_ gesture: UIPanGestureRecognizer) {
        // 1
        let tapLocation = gesture.location(in: self.sceneView)
        let results = self.sceneView.hitTest(tapLocation, types: .featurePoint)
 
        // 2
        guard let result = results.first else {
            return
        }
 
        // 3
        let translation = result.worldTransform.translation
 
        //4
        guard let node = self.node else {
            self.addBox(x: translation.x, y: translation.y, z: translation.z)
            return
        }
        node.position = SCNVector3Make(translation.x, translation.y, translation.z)
        self.sceneView.scene.rootNode.addChildNode(self.node)
    }
 
//5
extension float4x4 {
    var translation: float3 {
        let translation = self.columns.3
        return float3(translation.x, translation.y, translation.z)
    }
}

Розглянемо цей код:

  1. Визначаємо позицію кліку на екрані і передаємо його функцію hitTest нашої сцени, отримуємо масив ARHitTestResult, який визначає місце контакту з поверхнею.
  2. Якщо точки контакту були знайдені, ми отримуємо першу з них і рухаємося далі, в іншому випадку - завершуємо функцію.
  3. Використовуючи поле worldTransform точки дотику, визначаємо координати цієї точки в системі координат реального світу.
  4. Якщо об'єкт існує, ми змінюємо його положення, інакше викликаємо функцію додавання і передаємо їй координати точки дотику.
  5. Це розширення для float4×4, яке робить роботу з координатами більш зручною.

Запустивши код і натиснувши на поверхню, ми побачимо наш різнокольоровий куб:

Масштабування об'єкта

Тепер додамо функцію масштабування нашого куба. Ми зробимо так, щоб наш куб розтягувався і звужувався за допомогою жесту стискання.

Як і в попередньому прикладі, ми додамо функцію для визначення стискання і викличемо її в viewDidLoad().

   private func addPinchGesture() {
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(didPinch(_:)))
        self.sceneView.addGestureRecognizer(pinchGesture)
    }
 

Потім ми додамо функцію, яка буде розтягувати та звужувати наш куб до певного розміру.

  @objc func didPinch(_ gesture: UIPinchGestureRecognizer) {
 
        switch gesture.state {
        // 1
        case .began:
            gesture.scale = CGFloat(node.scale.x)
        // 2
        case .changed:
            var newScale: SCNVector3
	// a
            if gesture.scale < 0.5 {
                newScale = SCNVector3(x: 0.5, y: 0.5, z: 0.5)
	// b
            } else if gesture.scale > 3 {
                newScale = SCNVector3(3, 3, 3)
	// c
            } else {
                newScale = SCNVector3(gesture.scale, gesture.scale, gesture.scale)
            }
	// d
            node.scale = newScale
        default:
            break
        }
    }

Давайте розглянемо цей код:

  1. По-перше - беремо жест стискання і додаємо до нього масштаб нашого куба для випадків, коли куб вже був розтягнутий і ми хочемо продовжити масштабування, а не починати його з самого початку.
  2. Під час розтягування або звуження:
  • Якщо масштаб менше 0.5, ми залишаємо його на рівні 0.5
  • Якщо масштаб перевищує 3, ми залишаємо його на рівні 3
  • У всіх інших випадках встановлюємо масштаб, який відповідає жесту стискання.
  • Встановлюємо масштаб для нашого вузла.

Обертання об'єкта

Тепер додамо функцію обертання нашого об'єкта навколо осі Y. Ми змусимо наш куб обертатися навколо осі Y за допомогою жесту обертання.

Як і в попередньому прикладі, ми додамо функцію для визначення жесту обертання і викличемо її в viewDidLoad().

 private func addRotationGesture() {
        let panGesture = UIRotationGestureRecognizer(target: self, action: #selector(didRotate(_:)))
        self.sceneView.addGestureRecognizer(panGesture)
    }

І обертання самого куба:

  private var lastRotation: Float = 0
 
    @objc func didRotate(_ gesture: UIRotationGestureRecognizer) {
        switch gesture.state {
        case .changed:
            // 1
            self.node.eulerAngles.y = self.lastRotation + Float(gesture.rotation)
        case .ended:
            // 2
            self.lastRotation += Float(gesture.rotation)
        default:
            break
        }
    }

Давайте розглянемо цей код:

  1. Змінюємо кут Y у вузлі.
  2. Зберігаємо останнє значення повороту.

Майбутнє ARKit

На конференції для розробників WWDC 2019 Apple представила оновлену платформу ARKit 3. ARKit 3 йде далі, ніж будь-коли раніше, використовуючи People Occlusion і показуючи AR-контент людям природним чином, перед ними або позаду них, відстежуючи до 3 людей одночасно, підтримуючи спільний доступ до сеансів і багато іншого. Використовуючи нові знання ARKit про людей, можна буде інтегрувати рух людей в додаток.

Висновок

Вітаємо вас! Ми створили невеликий додаток з доповненою реальністю. Тепер ви знаєте, як розробляти AR-додатки, налаштовувати проект, додавати віртуальні об'єкти, змінювати їхнє положення, масштабувати та обертати. ARKit - це велика тема, і в цій статті ми торкнулися лише деяких основ, але це лише верхівка великого айсберга під назвою ARKit. Я сподіваюся, що ця інформація була корисною для вас і бажаю вам успіхів у ваших починаннях.

Ви можете знайти повний демо-проект на on Bitbucket