Придайте своей новой реальности новый облик

Вы спрашиваете себя, почему вы хотите изменить текстуру на узле (узел - это любой объект в сцене SceneKit)?

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

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

Начиная

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

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

Совершенно верно - мы собираемся создавать планетные тела с помощью нашего приложения. Обязательно назовите их earth, moon и sun соответственно и поместите их прямо в папку Assets.xcassets.

В ViewController.swift начните с объявления следующих переменных чуть выше метода viewDidLoad():

let textures = ["earth", "moon", "sun"]
var currentIndex = 0
var currentTexture = ""

Убедитесь, что строки в массиве текстур имеют те же точные имена, что и текстуры в папке с ресурсами. Внутри метода viewDidLoad() замените там, где написано SCNScene(named: “art.scnassets/ship.scn”)!, на SCNScene(). Под этой строкой инициализируйте currentTexture первым элементом в textures, используя currentTexture = textures[currentIndex].

После метода viewWillDisappear() создайте следующую функцию:

func createSphere() -> SCNNode {
  let sphere = SCNSphere(radius: 1)     
  sphere.firstMaterial?.diffuse.contents = UIImage(named:    
  currentTexture)
  let sphereNode = SCNNode(geometry: sphere)
  sphereNode.name = "sphere"
  sphereNode.position = SCNVector3(0, 0, -3)
  return sphereNode
}

Само собой разумеется, что эта функция создает сферу в нашем трехмерном пространстве. Мы задаем сфере radius 1 метров (в соответствии с единицей измерения ARKit по умолчанию) и назначаем ей текстуру currentTexture, которая должна быть earth.

Затем мы создаем SCNNode() и назначаем геометрию его сферы, а также даем ей имя sphere, что будет важно при изменении текстуры. Затем мы помещаем его в трех метрах от камеры, когда приложение запускается и возвращается sphereNode.

В viewDidLoad() добавьте следующее под тем местом, где мы присвоили currentTexture:

sceneView.scene.rootNode.addChildNode(createSphere())

Протестируйте приложение на своем телефоне, и, если все пойдет хорошо, вы должны увидеть перед собой Землю дополненной реальности.

Жесткие жесты

Теперь приступим к изменению текстур с помощью сенсорного жеста. Под методом createSphere() реализуйте touchesBegan(_:with:) . Обратите внимание, что есть и другие способы реализовать сенсорный жест - это только один из них. Добавьте следующий код внутрь touchesBegan:

let touch = touches.first!
if touch.view == self.sceneView {
  let viewTouchLocation:CGPoint = touch.location(in: sceneView)
  
  guard let result = sceneView.hitTest(viewTouchLocation, options: nil).first else {
    return
  }
  if result.node.name == "sphere" {
    let node = result.node
    currentIndex = currentIndex == 0 ? 1 : currentIndex == 1 ? 2 : 0
    currentTexture = textures[currentIndex]
    node.geometry?.firstMaterial?.diffuse.contents = currentTexture
  }
}

Давайте рассмотрим этот кодовый блок.

Во-первых, мы получаем первый случай обнаружения касания.

Затем мы проверяем, находится ли касание в пределах sceneView (если вы следовали инструкциям, sceneView по умолчанию должен покрывать весь экран телефона, потому что у него автоматически нулевые поля с каждой стороны).

Затем мы получаем CGPoint координаты точки касания относительно экрана.

Затем мы убеждаемся, что запускаем sceneView’s hitTest, назначая его result; в противном случае мы return.

На этом этапе код может проверить, касаемся ли мы узла. Если имя узла, которого мы касаемся, sphere (которое мы использовали ранее), то нам нужно изменить текстуру сферы. Поскольку у меня всего три текстуры, я использую тернарный оператор для цикла currentIndex от 0 ➡ 1 ➡ 2, а затем обратно до 0. Затем я переназначаю currentTexture. И, наконец, я назначаю нашему узлу новый материал.

Ух! Запустите свой код, и вы должны получить такой результат, когда коснетесь сферы:

Это все! Я надеюсь, что это даст вам отправную точку для изменения текстур в ARKit. Вы можете ознакомиться с полным исходным кодом здесь.