ARKit은 처음 보면 다소 어렵게 느껴질 수 있지만, iOS 앱 개발 경험이 조금만 있어도 생각보다 어렵지 않습니다.
저는 직접 만들어 보며 배우는 스타일이라, ARKit에 익숙해지기 위해 간단한 앱들을 여러 개 만들어 보았습니다. 이 글에서는 간단한 얼굴 추적 앱을 만들면서 배운 내용을 정리해 공유하려 합니다.
전체 과정은 크게 3단계로 나눌 수 있습니다.
- 초기 설정 → 가장 먼저 카메라 권한을 요청하고, 기기가 ARKit을 지원하는지 확인합니다.
- 미소 추적 → ARKit으로 미소를 감지하기 시작합니다. 아마 여러분이 이 글을 찾아온 이유이기도 하죠.
- 사용자 인터페이스 → 미소에 반응하는 UI를 추가합니다.
이 글을 작성하는 시점 기준으로 Xcode 시뮬레이터는 전면 카메라를 지원하지 않습니다. 따라서 실제 기기가 필요하며, TrueDepth 카메라를 탑재한 기기(iPhone X 이상)여야 합니다.
마지막으로, 복사-붙여넣기 클럽 회원 여러분을 위해 모든 코드는 Github에 올려두었습니다.
초기 설정
Xcode를 열고 "SmileTracker"(또는 원하는 이름)라는 새 프로젝트를 생성하는 것부터 시작합니다.
본격적으로 얼굴 추적에 들어가기 전에 두 가지 작업이 필요합니다.
- 기기가 ARKit을 지원하는지 확인
- 카메라 접근 권한 획득
새 프로젝트에서 ViewController.swift 파일을 엽니다. 파일 상단의 import UIKit 바로 아래에 다음 줄을 추가하세요. import ARKit. 이제 Apple이 제공하는 강력한 기능들을 활용해 손쉽게 얼굴 추적을 구현할 수 있습니다.
다음으로 viewDidLoad 안에 아래 코드를 추가합니다.
guard ARFaceTrackingConfiguration.isSupported else {
fatalError("Device does not support face tracking")
}ARFaceTrackingConfiguration.isSupported는 불리언 값으로, 앱을 실행하는 기기가 얼굴 추적을 지원하면 true, 아니면 false를 반환합니다. 여기서는 얼굴 추적을 지원하지 않는 경우 치명적 오류(fatal error)와 함께 앱을 종료하도록 처리했습니다.
이제 카메라 사용 권한을 요청해 보겠습니다. viewDidLoad의 guard 문 아래에 다음 코드를 추가합니다.
AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in
if (granted) {
Dispatch.main.sync {
// 이 함수는 곧 구현할 예정입니다
self.setupSmileTracker()
}
} else {
fatalError("User did not grant camera permission!")
}
}여기서는 기기에 카메라 권한을 요청합니다. 사용자가 권한을 허용하면 미소 추적을 설정하는 함수를 실행합니다(지금은 에러가 표시되어도 걱정하지 마세요. 곧 이 함수를 구현할 것입니다).
함수를 Dispatch.main.sync로 감싸는 이유는, 이 함수 안에서 UI 요소를 추가하게 되는데 UI 작업은 반드시 메인 스레드에서 수행해야 하기 때문입니다.
또한 Info.plist에 Camera Usage Description도 추가해야 합니다. Info.plist를 열고 새 행을 추가하세요(마지막 행을 선택한 상태에서 enter 키를 누르면 됩니다).
새로 만든 행의 Key 열에 Privacy — Camera Usage Description를 입력하고, Type 열이 string으로 설정되어 있는지 확인합니다. Value 열은 비워두거나, 사용자에게 카메라 사용 목적을 설명하는 메시지를 입력할 수 있습니다.
완성된 Info.plist는 대략 다음과 같은 형태입니다.

여기까지 진행 상황을 테스트해 보고 싶다면, setupSmileTracker()를 호출하는 줄을 주석 처리하면 됩니다. 단, 나중에 주석 해제하는 것을 잊지 마세요.
지금 앱을 실행하면 카메라 권한을 허용할지 묻는 팝업이 나타납니다. 만약 거부하면, 앱이 정상적으로 실행되도록 설정 앱에서 직접 권한을 켜야 합니다.
앱이 크래시된다면 콘솔에서 앞서 작성한 두 가지 에러 메시지 중 하나를 확인해 무엇이 잘못됐는지 파악하세요.
미소 추적
ViewController.swift를 열고 ViewController 클래스 상단에 다음 변수를 추가합니다.
class ViewController: UIViewController {
let sceneView = ARSCNView()
override func viewDidLoad() {...}
}ARSCNView에는 iPhone이 AR 경험을 조율하는 데 사용하는 ARSession이 내장되어 있습니다. 우리는 sceneView의 ARSession을 활용해 전면 카메라로 사용자의 얼굴을 분석할 것입니다.
viewDidLoad 아래에 다음 함수를 추가합니다.
func setupSmileTracker() {
let configuration = ARFaceTrackingConfiguration()
sceneView.session.run(configuration)
sceneView.delegate = self
view.addSubview(sceneView)
}여기서는 얼굴 추적을 담당할 configuration을 생성하고, 이를 사용해 sceneView의 ARSession을 실행했습니다.
그런 다음 sceneView의 delegate를 self로 지정하고 뷰에 추가합니다.
Xcode가 ViewController가 ARSCNViewDelegate를 준수하지 않는다는 오류를 표시할 것입니다. 파일 상단의 ViewController 선언부로 이동해 다음과 같이 수정하세요.
class ViewController: ViewController, ARSCNViewDelegate {
...
}이제 ViewController 클래스에 다음 ARSCNViewDelegate 함수를 추가합니다(setupSmileTracker 아래에 위치).
func renderer(_renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
...
}renderer 함수는 씬(scene)이 업데이트될 때마다 호출되며, 사용자의 얼굴에 해당하는 ARAnchor를 전달해 줍니다.
얼굴 추적 경험을 더 쉽게 만들 수 있도록, Apple은 ARFacetrackingConfiguration으로 세션을 실행하면 자동으로 ARFaceAnchor를 생성해 세션에 추가합니다. 이 ARFaceAnchor는 ARAnchor 형태로 renderer 함수에 전달됩니다.
renderer 함수에 다음 코드를 추가합니다.
func renderer(_renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
// 1
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
// 2
let leftSmileValue = faceAnchor.blendshapes[.mouthSmileLeft] as! CGFloat
let rightSmileValue = faceAnchor.blendShapes[.mouthSmileRight] as! CGFloat
// 3
print(leftSmileValue, rightSmileValue)
}이 함수 안에서 많은 일이 일어나기 때문에 단계별로 번호를 붙였습니다(Ray Wenderlich 스타일이죠).
1단계에서는 ARAnchor를 ARFaceAnchor로 변환해 faceAnchor 변수에 할당합니다.
ARFaceAnchor에는 추적 중인 얼굴의 현재 위치와 방향, 위상(topology), 그리고 표정 정보가 담겨 있습니다.
ARFaceAnchor는 표정 정보를 blendShapes 변수에 저장합니다. blendShapes는 다양한 얼굴 특징에 해당하는 계수(coefficient)를 저장하는 딕셔너리입니다. 관심이 있다면 Apple 문서에서 전체 얼굴 특징 목록을 확인해 보시길 권합니다. (힌트: 찡그린 표정 추적 기능을 추가하고 싶다면 이 목록에서 방법을 찾을 수 있습니다.)
2단계에서는 faceAnchor.blendShapes를 사용해 mouthSmileLeft와 mouthSmileRight 키로 사용자 입꼬리의 좌우 미소 정도에 해당하는 CGFloat 값을 가져옵니다.
마지막으로 3단계에서는 두 값을 출력해 제대로 동작하는지 확인합니다.
이 시점에서 여러분의 앱은 다음 기능을 갖추고 있어야 합니다.
- 사용자에게 카메라 및 얼굴 추적 권한 요청
- ARKit으로 사용자의 표정 추적
- 입꼬리 좌우의 미소 정도를 콘솔에 출력
상당히 많은 진전을 이루었으니, 잠시 모든 것이 정상적으로 동작하는지 확인해 보겠습니다.
앱을 처음 실행하면 카메라 권한을 허용할지 묻는 화면이 나타납니다. 반드시 허용을 선택하세요.
그러면 빈 화면으로 전환되지만, 잠시 후 콘솔에 CGFloat 값들이 출력되기 시작할 것입니다(값이 표시되기까지 약간의 지연이 있을 수 있습니다).
폰을 향해 미소 짓으면 출력되는 값이 올라가는 것을 확인할 수 있습니다. 클수록 웃는 폭이 커진다는 의미입니다.
정상적으로 동작한다면 축하합니다! 에러가 발생한다면 기기가 얼굴 추적을 지원하는지, 그리고 카메라 권한이 켜져 있는지 다시 한번 확인하세요. 처음부터 이 가이드를 따라왔다면 두 경우 모두 콘솔에 에러가 출력됩니다.
사용자 인터페이스
이제 얼굴 추적이 가능해졌으니, 미소에 반응하는 UI를 만들어 보겠습니다.
먼저 파일 상단, sceneView 바로 아래에 smileLabel이라는 새 UILabel을 추가합니다.
class ViewController: UIViewController {
let sceneView = ARSCNView()
let smileLabel = UILabel()
...
}이 뷰가 사용자의 표정에 반응하는 역할을 맡습니다.
setupSmileTracker 함수 맨 아래에 다음 코드를 추가합니다.
smileLabel.text = "?"
smileLabel.font = UIFont.systemFont(ofSize: 150)
view.addSubview(smileLabel)
// 제약조건 설정
smileLabel.translatesAutoresizingMaskIntoConstraints = false
smileLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
smileLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true여기서 smileLabel에 기본적인 UI 속성을 부여하고, 화면 중앙에 배치되도록 제약조건을 설정했습니다. 앱을 실행하면 화면 중앙에 커다란 이모지 하나가 나타날 것입니다.

이모지가 표시되는 것을 확인했다면, ViewController에 다음 함수를 추가합니다.
func handleSmile(leftValue: CGFloat, rightValue: CGFloat) {
let smileValue = (leftValue + rightValue)/2.0
switch smileValue {
case _ where smileValue > 0.5:
smileLabel.text = "😄"
case _ where smileValue > 0.2:
smileLabel.text = "🙂"
default:
smileLabel.text = "😐"
}
} 이 함수는 사용자가 카메라를 향해 얼마나 크게 웃느냐에 따라 smileLabel의 이모지를 변경합니다. smileValue는 ARFaceAnchor가 알려준 좌우 미소 값의 평균으로 계산합니다(아주 과학적이죠, 알고 있습니다).
이 값을 switch문에 넣으면, 사용자가 많이 웃을수록 이모지도 더 밝은 표정이 됩니다.
마지막으로 renderer 함수로 돌아가 하단에 다음 코드를 추가해 좌우 미소 값을 handleSmile에 연결합니다.
DispatchQueue.main.async {
self.handleSmile(leftValue: leftSmileValue, rightValue: rightSmileValue)
}역시 UI를 변경하는 작업이므로 메인 스레드에서 수행해야 하기 때문에 DispatchQueue를 사용했습니다.
앱을 실행하면 이제 미소의 크기에 따라 이모지가 변하는 것을 볼 수 있습니다.
아래 GIF에는 실제 동작 모습을 보여드리기 위해 제 얼굴과 카메라 출력 화면을 함께 넣었습니다.

여러분의 앱에는 카메라 출력이 없겠지만, ARSCNView인 sceneView를 superview에 추가하고 크기를 지정하면 손쉽게 넣을 수 있습니다.
마무리
이 글이 ARKit으로 앱 개발을 시작하는 데 도움이 되었기를 바랍니다.
이 앱을 더 확장하고 싶다면 앞서 언급한 추적 가능한 얼굴 특징 전체 목록을 확인해 보세요. 찡그린 표정 감지 기능으로 확장하는 방법에 대한 힌트도 남겨두었습니다.
직접 만든 멋진 프로젝트가 있다면 댓글로 공유해 주세요. 저도 아직 ARKit 초보라 더 복잡한 앱 사례를 보면 큰 도움이 될 것 같습니다.
이 앱의 전체 코드는 피드백과 질문을 받기 위해 Github에 공개해 두었습니다. 읽어주셔서 감사합니다. 행운을 빕니다!
끝까지 읽어주셔서 정말 감사합니다! 이 글이 마음에 드셨다면 Twitter에서 저를 팔로우해 주세요. 진행 중인 글과 근황을 공유하고 있습니다.