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)
帽子的逼真程度取决于它相对于脸部的位置以及它在场景中的位置(即帽子前面的特征应该遮挡帽子本身)。考虑到这一点,您会希望脸部遮挡帽子。因此,您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对我来说效果很好。