你能获得什么

  1. ARKit的基本使用方法
  2. 人脸滤镜
  3. 举一反三学会其他内容

原理

通过人脸追踪技术,将自己绘制的贴图贴到人脸上。

结果

arkit_plugin支持android吗_贴图

开始

需要导入的库

import UIKit
import SceneKit
import ARKit

设备检测以及摄像头权限

AR的应用毋庸置疑需要摄像头的权限,所以在调用的时候首先要在Info.plist文件中添加字段CameraUsageDescription,在Value处填写应用调用摄像头的目的,例如"该应用需要调用您摄像头来进行AR操作".
人脸追踪的技术需要前置的TrueDepth摄像头(iPhone X及以上),对手机设备有要求,调用人脸追踪技术的时候需要先检查当前设备是否支持。如下代码

//检测当前设备是否支持AR
    private lazy var isSupproted:Bool = {
        guard ARConfiguration.isSupported else{
            return false
        }
        guard ARFaceTrackingConfiguration.isSupported else{
            return false
        }
       return true
    }()

前置内容显示

增加现实,目的就是将虚拟的物体与现实世界相结合起来,首先需要显示内容。虚拟内容通过ARSCNView显示。

private lazy var sceneView:ARSCNView = {
        let view = ARSCNView(frame: self.view.frame)
        view.session.delegate = self
        view.delegate = self
        return view
    }()

再加sceneView添加到主视图中

override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(sceneView)
    }

将视图添加后便需要让数据流展现在View上,为了性能我们可以在ViewController隐藏的时候让sceneView的数据流停止,在ViewController显示的时候重新运行。

override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        sceneView.session.pause()
    }
    
override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if isSupproted{
        //开始捕获视频流
            sceneView.session.run(faceConfiguration, options: [.removeExistingAnchors,.resetTracking])
        }
    }

到现在为止,没有什么意外的话,你的应用应该可以显示前置摄像头的内容了,虽然看上去好像跟普通的前置没有区别,实际上前置摄像头一直在追踪着你的人脸,只是没有内容输出。

虚拟节点的显示

我们在上面操作后便获得了现实场景,现在尝试着将虚拟节点添加上去吧!那么虚拟节点的渲染是通过ARSCNViewDelegate回调实现的,在这里主要使用到的方法是

///处理数据流出现问题时的毁掉
func session(_ session: ARSession, didFailWithError error: Error)	
///当人脸开始移动的时候,追踪人脸并且将贴图贴到指定地方
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor)
///相当于初始化,将虚拟节点贴到现实场景中
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor)

SCNNode

这个便是虚拟节点类,包含着节点的构成信息(geomerty),构成信息中的材料(firstMaterial),包含着虚拟节点的由什么图像组成。

ARSCNFaceGeometry

这个便是苹果自带的人脸的构成信息,可以直接生成,它的模型成如下所示,你可以想象它检测到你人脸的位置,并且将这些虚拟的模型添加在人脸中,实现滤镜贴图,但是光光这样贴图是没有东西的,它缺少了“皮”,你需要给这个模型皮肤。

arkit_plugin支持android吗_swift_02


那么我们先准备好如下皮肤,这个是展开图,你可以把它当作3D的面具贴合在你的脸上

arkit_plugin支持android吗_swift_03

开始渲染

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        //保证device以及anchor为脸部anchor
        guard let device = sceneView.device,let _ = anchor as? ARFaceAnchor else{
            return nil
        }
        //1.
        let faceGeometry = ARSCNFaceGeometry(device: device)
        //2.
        let rootNode = SCNNode(geometry: faceGeometry)
        //imageName指的是你存储上述人脸皮肤时候的文件名
        //3.
        faceGeometry?.firstMaterial?.diffuse.contents = UIImage(named: imageName)
        //4.
        rootNode.name = "root"
        return rootNode
    }
1.生成一个人脸的构成信息
2.生成一个虚拟节点,并且这个节点的构成信息是人脸,相当于创造了一个人脸模型的虚拟节点,而且模型的每一个点位置一一对应到现实中
3.给这个人脸模型穿上皮肤,contents可以是颜色、数字、图像、字符串...
4.节点打上标志,为了以后方便查找这个虚拟节点

没有错就是上述这几行代码便可以将皮肤贴到你的人脸中,是不是很简单,但是真的要去理解起来却需要花费一定的时间。

效果图

arkit_plugin支持android吗_swift_04

渲染更新

那么在转动摄像头,张开嘴巴或者是动动眉毛的时候也希望可以很好的贴合,所以我们需要去更新面部的锚点。

//动态更新根据人脸
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard let faceAnchor = anchor as? ARFaceAnchor,let faceGeometry = node.geometry as? ARSCNFaceGeometry else{
            return
        }
        faceGeometry.update(from: faceAnchor.geometry)
    }

滤镜效果

如何制作自己需要的滤镜效果呢,那么你可以根据上面面具作为定位图,在定位图中去绘制自己希望的滤镜,如下图

arkit_plugin支持android吗_xcode_05


这里要注意图片需要png格式,可以保证没有白底,如果有白底的话效果会是这样的

arkit_plugin支持android吗_滤镜_06

最后

翻阅了很多的资料,一篇讲的是如何将Emoji表情添加到指定的位置,那篇文章如果没有看懂,可以这样理解,将虚拟的节点添加到主节点(虚拟人脸节点),获取到了人脸的点位anchor.geometry.vertices[9](对应的是鼻子的中心),将虚拟节点放置到指定位置。
那么人脸的滤镜大致就是这样实现的,为什么你摄像头如何移动它都能跟踪到是因为,它是根据人脸的锚点去进行定位的,所以我们在贴滤镜时可以简单根据上述操作进行。