翻译完了才发现已经有人翻译过了,而且还是自己收藏过的,服了自己了。
不过苹果的文档也有些许更新,也总算是过了一遍,大家随意看看,有示例代码运行效果截图,整体效果还是不错的。ps:iPhone X也是不错的😈。
使用iPhone X上的TrueDepth相机来根据用户脸型放置3D内容,并根据用户表情做动画。
下载官网demo
SDKs
iOS 11.0+
Xcode 9.1+
概述
这个示例app展示了一个简单的界面,让你可以在拥有TrueDepth 前置相机的设备(iPhone X)上选择4种AR特效。
- 只有相机拍摄的视图,没有AR特效。
- ARKit 提供的脸部网格(mesh),并提供自动的现实世界光线感知环境。
- 贴在用户脸上的虚拟3D内容。
- 一个简单的机器人形象,面部表情会跟用户一致。
用示例app中的"+"按钮来选择不同的效果,如下图所示。
使用SceneKit视图来新建一个脸部追踪Session
跟其他ARKit的应用一样,脸部追踪需要配置并运行一个session(一个ARSession对象),并在同一个视图里同时渲染相机图像和虚拟内容。如需更多关于session和view的详细教程,参考 About Augmented Reality and ARKit 和Building Your First AR Experience。这个示例使用SceneKit来显示AR体验,你也可以用SpriteKit 或者用Metal来创建你自己的渲染器(参考ARSKView和Displaying an AR Experience with Metal)。
脸部追踪跟其他ARKit的应用的不同之处在于配置session的所使用的类不同。要使用脸部追踪,你得创建一个ARFaceTrackingConfiguration的实例,配置一下它的属性,然后传给view的AR session的run(_:options:)
方法,如下:
// 判断是否支持FaceTracking
guard ARFaceTrackingConfiguration.isSupported else { return }
// 创建配置类
let configuration = ARFaceTrackingConfiguration()
configuration.isLightEstimationEnabled = true
// run
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
追踪脸部的位置和旋转
当脸部追踪激活的时候,ARKit自动向正在运行的AR session中添加ARFaceAnchor
对象,此对象包含用户脸部的位置和旋转信息。
提示
ARKit 只能检测和提供以为用户的脸部。如果摄像头捕捉到多个脸,ARKit会挑选最大或者最能清晰分辨的脸部来识别。
在使用基于SceneKit的AR体验时,你可以在renderer(_:didAdd:for:)
方法(遵循ARSCNViewDelegate协议)添加一个可以响应脸部锚点的3D物件。ARKit会在锚点上添加一个SceneKit节点(node),并在每一帧更新node的位置和旋转属性,因此你添加在这个节点上的任意SceneKit内容都会自动跟随用户脸部的位置和旋转运动。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
// Hold onto the `faceNode` so that the session does not need to be restarted when switching masks.
// 持有`faceNode`可以在换面具时不需要重启session
faceNode = node
serialQueue.async {
self.setupFaceNodeContent()
}
}
在这个示例中,renderer(_:didAdd:for:)
方法调用了setupFaceNodeContent
方法来向faceNode
添加SceneKit内容。举个🌰,如果你要改变demo中的showsCoordinateOrigin
变量,demo app就会在这个节点(faceNode?)上添加一个虚拟x/y/z轴,指示脸部锚点的原点和坐标系。
使用脸部几何来给用户脸部建模
ARKit提供了契合用户脸部尺寸、形状、拓扑结构(面貌结构)和当前面部表情的粗略3D网格(学过ABAQUS的可能比较容易理解)。ARKit中提供ARSCNFaceGeometry类,能让你轻易在SceneKit中把网格可视化。
你的AR体验可以使用这个网格来放置或者渲染一些看上去贴在脸上的内容。比如你可以通过在这个几何网格上添加一些半透明的纹理来在用户皮肤上画一个虚拟纹身或模拟化妆。
要创建一个SceneKit脸部几何对象,用你SceneKit视图使用的Metal device来初始化一个ARSCNFaceGeometry变量:
// This relies on the earlier check of `ARFaceTrackingConfiguration.isSupported`.
// 要前置判断是否支持ARFaceTrackingConfiguration
let device = sceneView.device!
let maskGeometry = ARSCNFaceGeometry(device: device)!
这段示例代码的setupFaceNodeContent
方法(上文提到过)向scene添加了一个包含脸部几何的node。通过使这个node成为脸部锚点的子node,脸部模型会自动追踪用户脸部的位置和旋转。
要在用户眨眼、说话或做不同的表情时让模型随用户脸型变化,你需要在renderer(_:didUpdate:for:)
代理回调方法中取出更新的脸部网格。
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
virtualFaceNode?.update(withFaceAnchor: faceAnchor)
}
然后在你需要匹配的scene中通过将新脸部网格传入update(from:)
方法来更新ARSCNFaceGeometry对象:
func update(withFaceAnchor anchor: ARFaceAnchor) {
let faceGeometry = geometry as! ARSCNFaceGeometry
faceGeometry.update(from: anchor.geometry)
}
在用户的脸上放置3D内容
ARKit提供的另一个脸部网格的应用是:在你的scene中创建一个遮挡几何体。遮挡几何体是指一个不渲染任何可见内容,允许相机图像(实际物体)穿越展示,但可以遮挡scene中其他的虚拟内容的3D模型。
这项技术实现了虚拟物体与真实面部相互作用的假象,即使脸是2D的相机图像而虚拟内容是个3D的渲染物体。举个栗子,如果你放置一个遮挡几何体和一个虚拟眼镜在用户脸上,脸部可以挡住镜框。
要在脸上创建一个遮挡几何体,首先要创建一个ARSCNFaceGeometry对象geometry
,就像上一个例子一样。不同之处是上一个例子是用一个可见物体配置SceneKit的材质,这次要将材质设置为在渲染时使用深度而非颜色来渲染:
geometry.firstMaterial!.colorBufferWriteMask = []
occlusionNode = SCNNode(geometry: geometry)
occlusionNode.renderingOrder = -1
由于材料渲染的是深度,SceneKit渲染的其他物体会正确的显示在它的前面或者后面。但因为材料并不渲染颜色,相机图像会在它所在的位置出现。示例app用一个在用户眼前的SceneKit物体(一个超大的AR文字),结合这个技术创建了一个逼真的“AR”被用户鼻子遮挡的效果。
让一个复合形状的角色活起来
除了上述两个对于脸部网格的应用之外,ARKit还以blendShapes字典的方式提供一个更抽象的用户脸部表情模型。你可以使用这个字典给出的系数值来控制你自己的2D或者3D模型的动画参数,创建一个跟随用户实际脸部活动和表情的对象(比如一个狗狗头像)。
作为一个复合形状动画的基本范本,这个示例包含了一个简易的机器人形象🤖模型,这个模型是使用SceneKit原生形状创建的(参考源码中的robotHead.scn文件)。
要获取用户当前的面部表情,请查阅blendShapes字典,这个字典从代理回调renderer(_:didUpdate:for:)
的面部锚点中取得:
func update(withFaceAnchor faceAnchor: ARFaceAnchor) {
blendShapes = faceAnchor.blendShapes
}
然后,检查这个字典的键值对来计算你的模型的动画参数。总共有52个独立的ARFaceAnchor.BlendShapeLocation系数。你的app可以使用必要的参数来创建你脑海中的艺术化效果。在这个示例中,RobotHead
类做了相关的计算,将eyeBlinkLeft和eyeBlinkRight映射到机器人眼睛一个轴的scale值;把jawOpen映射到机器人的下巴位置的偏移距离。
var blendShapes: [ARFaceAnchor.BlendShapeLocation: Any] = [:] {
didSet {
guard let eyeBlinkLeft = blendShapes[.eyeBlinkLeft] as? Float,
let eyeBlinkRight = blendShapes[.eyeBlinkRight] as? Float,
let jawOpen = blendShapes[.jawOpen] as? Float
else { return }
eyeLeftNode.scale.z = 1 - eyeBlinkLeft
eyeRightNode.scale.z = 1 - eyeBlinkRight
jawNode.position.y = originalJawY - jawHeight * jawOpen
}
}