Итак, вот ответ на мой вопрос.
Во-первых, чтобы статически поместить объект в центр сцены, это означает, что вы не хотите, чтобы объект двигался во время движения камеры, вам нужно установить его положение в текущее положение камеры.
Чтобы узнать текущее местоположение камеры, нам нужно получить значение pointOfView .
pointOfView
содержит текущее местоположение и ориентацию камеры.
Один из вариантов использования - когда нам нужно добавить узлы перед камерой.
Местоположение и ориентация кодируются внутри pointOfView
в transformMatrices SCNMatrix4
,
Из документации Apple:
На рисунке ниже показаны конфигурации матрицы для некоторых наиболее распространенных
преобразования, которые вы можете сделать. Умножение любой координаты на
Тождественное преобразование возвращает ту же самую координату. Для других
преобразования, как координата изменяется полностью зависит от
какие компоненты матрицы вы меняете. Например, чтобы перевести вдоль
только по оси X, вы бы поставили ненулевое значение для компонента TX
матрицы перевода и оставьте значения ty и tz равными 0. Для
повороты, вы бы предоставили соответствующие значения синуса и косинуса
целевой угол поворота. Матричные конфигурации для
![enter image description here](https://i.stack.imgur.com/RqHmJ.png)
Pheeeew ...!
Теперь возьмите pointOfView
в теле вашего класса, а не в методах ARSCNViewDelegate
, если вы сделаете это в методе renderer(_nodeFor:)
, тогда ваш объект будет следовать геометрии лица:
guard let pointOfView = self.sceneView.pointOfView else { return }
и затем вы можете расположить свой объект в центре экрана:
DispatchQueue.main.async {
pointOfView.addChildNode(yourNode)
}
Так что теперь объект центрируется перед камерой, и он не будет двигаться соответственно с движением камеры.
затем для перемещения объекта путем наклона головы вверх / вниз нам нужно реализовать ARSCNViewDelegate
и вызвать:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
этот метод просит делегата предоставить узел SceneKit, соответствующий вновь добавленной привязке, которая в моем сценарии меня интересует FaceAnchor.
Я назначил геометрию лица для faceAnchor с прозрачностью 0, потому что мне не нужно, чтобы он был видимым, просто для отслеживания положения лица через этот узел, когда лицо перемещается, вызывается метод didUpdate
, и тогда мы можем обновите узлы или что-то еще в didUpdate
методе, потому что он вызывается всякий раз, когда целевой узел перемещается.
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
let faceTransform = faceAnchor.transform
let positionY = faceLocation.columns.2.y
let positionX = faceLocation.columns.2.x
let horizentalLine = Int(positionY * 100)
self.horizentalNode.eulerAngles = SCNVector3(horizentalLine.degreeToRadians, 0, 0)
Как я уже говорил, внутри каждого узла / якоря есть свойство, называемое transform, которое представляет собой матрицу, кодирующую положение, ориентацию и масштаб якоря относительно мирового координатного пространства сеанса AR, в котором находится якорь.
вкратце: это как-то связано с 3-х мерными метриками.
если выяснилось, что значения y и x в столбце № 2 - это горизонтальное и вертикальное движение головы, то небольшая математика там + расширение degreeToRadians
просто для преобразования значения для eulerAngles
матриц вращения.