【问题标题】:How to position SceneNode always at the center of the sceneView while using ARFaceTrackingConfiguration如何在使用 ARFaceTrackingConfiguration 时将 SceneNode 始终定位在场景视图的中心
【发布时间】:2019-04-29 15:10:31
【问题描述】:

我已经使用 ARFaceTrackingConfiguration 会话设置了 SceneView,并在场景资源中创建了一个虚拟 3D 模型。
模型是在场景视图中导入的,但它会随着相机的移动而相应移动,我需要将模型位置固定在场景视图的中心。
下图展示了我想要实现的目标。
所以 3D 模型不应该随着相机的移动而移动。

@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
}

【问题讨论】:

  • 你好,Shahriar,我正在做面部跟踪,想知道我应该把guard let pointOfView = self.sceneView.pointOfView else { return }DispatchQueue.main.async { pointOfView.addChildNode(yourNode) }放在哪里
  • 我想知道你定义的faceLocation在哪里?

标签: swift xcode arkit


【解决方案1】:

所以这是我自己问题的答案。

首先静态放置一个物体在sceneView的中间,也就是说你不希望物体在摄像机移动的时候移动,你需要将它的位置设置为摄像机当前的朝向位置。 要获取相机的当前位置,我们需要访问pointOfView 值。 pointOfView 包含cameraView的当前位置和方向 一个用例是当我们需要在相机前面添加节点时。 位置和方向在 pointOfView 内部编码为 transformMatrices SCNMatrix4 . 来自 Apple 文档:

下图显示了一些更常见的矩阵配置 您可以进行的转换。将任意坐标乘以 恒等变换返回完全相同的坐标。对于其他 变换,如何修改坐标完全取决于 您更改了哪些矩阵组件。例如,一起翻译 仅 x 轴,您将为 tx 组件提供一个非零值 的平移矩阵,并将 ty 和 tz 值保留为 0。对于 旋转,您将提供适当的正弦和余弦值 目标旋转角度。矩阵配置

呼……! 现在在您的类主体中获取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 维指标有关。 如果发现第 2 列中的 y 和 x 值是头部的水平和垂直移动,那么这里的小数学 + degreeToRadians 扩展只是将值转换为 eulerAngles 旋转矩阵。

【讨论】:

  • 你好 Shahriar 如果我要在头部向左或向右倾斜时触发一个事件,就像在这个过滤器上看到的那样 - instagram.com/stories/highlights/17849968714897293 有没有办法修改你的解决方案?我让 SCNNode 与鼻子的位置一起移动,但触发向左或向右倾斜的均匀倾斜似乎很棘手。
  • @DesperateLearner 你找到解决方案了吗?你知道把guard let pointOfView = self.sceneView.pointOfView else { return }放在哪里吗?最佳
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2011-08-20
相关资源
最近更新 更多