ARKit 面部跟踪 SceneKit 对象移动不正确

use*_*617 2 ios scenekit arkit

我无法理解 SceneKit 变换并将对象锚定到检测到的面部。我创建了一个人脸检测应用程序,并成功应用了带纹理和不带纹理的蒙版。我还成功应用了由文本(“00”)制成的“眼镜”,包括遮挡节点。

在这两种情况下,对象都会按预期随面部移动。然而,当我在 ScendKit 中创建一个由两个圆柱体制成的简单帽子时,其行为完全出乎意料。

首先,我似乎无法将帽子固定在脸上,但必须调整变换,使帽子几乎在每张脸上都出现在不同的位置。更糟糕的是,帽子的移动方向与脸部相反。将用户脸部向左旋转,帽子向右移动。将脸部向上旋转,帽子向下移动。

在此输入图像描述 在此输入图像描述

显然,我在这里遗漏了一些关于将对象锚定到面部的重要信息。任何指导将不胜感激。

Xcode 10 beta 3,在 iPhone X 上运行的 iOS 11.4.1。

帽子、眼镜、面具有一个单独的类:

class Hat : SCNNode {

    init(geometry : ARSCNFaceGeometry) {

        geometry.firstMaterial?.colorBufferWriteMask = []
        super.init()
        self.geometry = geometry

        guard let url = Bundle.main.url(forResource: "hat", withExtension: "scn", subdirectory: "Models.scnassets") else {fatalError("missing hat resource")}
        let node = SCNReferenceNode(url: url)!
        node.load()

        addChildNode(node)

    }//init

    func update(withFaceAnchor anchor : ARFaceAnchor) {
        let faceGeometry = geometry as! ARSCNFaceGeometry
        faceGeometry.update(from: anchor.geometry)
    }//upadate


    required init?(coder aDecoder: NSCoder) {
        fatalError("(#function) has not been implemented")
    }//r init

}//class
Run Code Online (Sandbox Code Playgroud)

ViewController 中的几个函数:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {

    guard let faceAnchor = anchor as? ARFaceAnchor else {return}

    updateMessage(text: "Tracking your face")

    switch contentTypeSelected {
    case .none:
        break
    case .mask:
        mask?.update(withFaceAnchor: faceAnchor)
    case .glasses:
        glasses?.update(withFaceAnchor: faceAnchor)
    case .hat:
        hat?.update(withFaceAnchor: faceAnchor)
    }//switch

}//didUpdate

func createFaceGeometry() {
    updateMessage(text: "Creating face geometry")

    let device = sceneView.device!

    let maskGeometry = ARSCNFaceGeometry(device: device)!
    mask = Mask(geometry: maskGeometry, maskType : maskType)

    let glassesGeometry = ARSCNFaceGeometry(device: device)!
    glasses = Glasses(geometry: glassesGeometry)

    let hatGeometry = ARSCNFaceGeometry(device: device)!
    hat = Hat(geometry: hatGeometry)

}//createFaceGeometry
Run Code Online (Sandbox Code Playgroud)

bey*_*ulf 6

帽子的逼真程度取决于它相对于脸部的位置以及它在场景中的位置(即帽子前面的特征应该遮挡帽子本身)。考虑到这一点,您会希望脸部遮挡帽子。因此,您init应该Hat使用面部几何形状设置一个遮挡节点:

let occlusionNode: SCNNode

 init(geometry: ARSCNFaceGeometry) {

    /*
     Taken directly from Apple's sample code https://developer.apple.com/documentation/arkit/creating_face_based_ar_experiences
     */
    geometry.firstMaterial!.colorBufferWriteMask = []
    occlusionNode = SCNNode(geometry: geometry)
    occlusionNode.renderingOrder = -1

    super.init()

    addChildNode(occlusionNode)

    guard let url = Bundle.main.url(forResource: "hat", withExtension: "scn", subdirectory: "Models.scnassets") else {fatalError("missing hat resource")}
    let node = SCNReferenceNode(url: url)!
    node.load()

    addChildNode(node)
}
Run Code Online (Sandbox Code Playgroud)

这将允许面部出现在 z 深度大于面部网格的任何虚拟对象的前面。

您还需要进行更改let hatGeometry = ARSCNFaceGeometry(device: device)!let hatGeometry = ARSCNFaceGeometry(device: device, fillMesh: true)!否则帽子会通过眼睛看到,从而产生不可思议的不良效果。

下一个问题是放置帽子,使其在场景中看起来可信。

因为我们希望脸部遮挡帽子的大部分,所以最好将其直接放置在脸部几何体顶部的 y 轴上。为了成功做到这一点,您可能希望帽子的枢轴点位于帽子几何形状的底部中心,并位于 .scn 文件中的 x = 0, y = 0 处。例如,场景编辑器和节点检查器可能看起来像:

场景编辑器设置 节点检查器设置

然后func update(withFaceAnchor anchor : ARFaceAnchor)你可以说

func update(withFaceAnchor anchor : ARFaceAnchor) {
    let faceGeometry = geometry as! ARSCNFaceGeometry
    faceGeometry.update(from: anchor.geometry)
    hat.position.y = faceGeometry.boundingSphere.radius
} 
Run Code Online (Sandbox Code Playgroud)

最后,对于帽子的 z 位置,您可能需要一个稍微负的值,因为帽子的大部分位于人脸后面。-0.089对我来说效果很好。

AR帽子直接戴上 AR 帽子轻微轮廓