Как позиционировать SceneNode всегда в центре сценыView при использовании ARFaceTrackingConfiguration - PullRequest
0 голосов
/ 29 апреля 2019

Я настроил SceneView с сеансом ARFaceTrackingConfiguration и создал фиктивную 3D-модель в ресурсах Scene.
Модель импортируется в сцену, но она движется в соответствии с движением камеры, мне нужно исправить положение модели в центре сцены.
На изображении ниже показано, чего я пытаюсь достичь.
Поэтому 3D-модель не должна двигаться в зависимости от движения камеры.

enter image description here

@IBOutlet var sceneView: ARSCNView!
let scene = SCNScene(named: "art.scnassets/TEST.scn")!
var contentNode: SCNNode?

override func viewDidLoad() {
    super.viewDidLoad()

    // Set the view's delegate
    sceneView.delegate = self

    // Show statistics such as fps and timing information
    sceneView.showsStatistics = true

    sceneView.scene = self.scene
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Create a session configuration
    let configuration = ARFaceTrackingConfiguration()
    configuration.isLightEstimationEnabled = true

    // Run the view's session
    sceneView.session.run(configuration)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Pause the view's session
    sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    guard let faceAnchor = anchor as? ARFaceAnchor else { return nil }

    let faceGeometry = ARSCNFaceGeometry(device: sceneView.device!)!

    self.contentNode = SCNNode(geometry: faceGeometry)

    return self.contentNode
}

1 Ответ

0 голосов
/ 02 мая 2019

Итак, вот ответ на мой вопрос.

Во-первых, чтобы статически поместить объект в центр сцены, это означает, что вы не хотите, чтобы объект двигался во время движения камеры, вам нужно установить его положение в текущее положение камеры. Чтобы узнать текущее местоположение камеры, нам нужно получить значение pointOfView . pointOfView содержит текущее местоположение и ориентацию камеры. Один из вариантов использования - когда нам нужно добавить узлы перед камерой. Местоположение и ориентация кодируются внутри pointOfView в transformMatrices SCNMatrix4 , Из документации Apple:

На рисунке ниже показаны конфигурации матрицы для некоторых наиболее распространенных преобразования, которые вы можете сделать. Умножение любой координаты на Тождественное преобразование возвращает ту же самую координату. Для других преобразования, как координата изменяется полностью зависит от какие компоненты матрицы вы меняете. Например, чтобы перевести вдоль только по оси X, вы бы поставили ненулевое значение для компонента TX матрицы перевода и оставьте значения ty и tz равными 0. Для повороты, вы бы предоставили соответствующие значения синуса и косинуса целевой угол поворота. Матричные конфигурации для

enter image description here

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 матриц вращения.

...