티스토리 뷰

728x90
반응형

저번 포스팅에는 face tracking을 해보았는데요, 이어서 eye tracking을 해보겠습니다.

이렇게 제가 눈을 깜박일때마다 로봇박스 눈도 따라오게 해주겠습니다.

 

 

[1] eyeLeftNode, eyeRightNode를 가져오기

 

robotHead.scn 파일을 들어가보면

eyeLeft랑 eyeRight 라는 childNode가 있습니다.

 

 

 

 

이런식으로 가져올 수 있습니다. 

let resourceName = "robotHead"
let contentNode = SCNReferenceNode(named: resourceName)
let eyeLeftNode = contentNode.childNode(withName: "eyeLeft", recursively: true)
let eyeRightNode = contentNode.childNode(withName: "eyeRight", recursively: true)

 

 

[2] blendShapes 

 

ARFaceAnchor에는 얼굴 표정과 관련된 정보를 주는 blendShapes 딕셔너리가 있습니다.

이 딕셔너리의 키값 을 살펴보면 눈, 코, 입, 턱 등에 관한 다양한 정보를 주는 것 같아요 👍

 

저는 눈깜박이는 정보를 얻어야하니까 eyeBlinkLeft랑 eyeBlinkRight 라는 키값을 사용해줄것입니다

 

 

왼쪽 눈을 다 뜨면 eyeBlinkLeft의 값은 0,

왼쪽 눈을 다 감으면 eyeBlinkLeft의 값은 1 입니다.

 

눈을 깜박깜박 거리면 0에서 1 사이의 값을 주겠죠?!

 

 

 

 

[3] node가 업데이트 될때마다 eyeLeftNode, eyeRightNode의 scale값 변경하기

 

renderer(_:didUpdate:for:) 이 메소드안에서 업데이트 시켜주면 됩니다.

 

그 전에 scale 값에 따라서 모양이 어떻게 달라지는 지 살펴볼게요-! 

 

1) scale.x


scale.x가 1일때

eyeLeftNode.scale.x = 1
eyeRightNode.scale.x = 1

 

scale.x가 0일때

eyeLeftNode.scale.x = 0
eyeRightNode.scale.x = 0

 

 

2) scale.y

 

scale.y가 1일때

eyeLeftNode.scale.y = 1
eyeRightNode.scale.y = 1

 

scale.y가 0일때

eyeLeftNode.scale.y = 0
eyeRightNode.scale.y = 0

 

 

(막 번쩍번쩍 거림)

 

 

3) scale.z

 

scale.z = 1일때

eyeLeftNode.scale.z = 1
eyeRightNode.scale.z = 1

 

scale.z = 0일때

eyeLeftNode.scale.z = 0
eyeRightNode.scale.z = 0

 

 

 

 

아무튼 scale이 1이여야지 기존 형태를 유지합니다. (눈뜬 모양)

근데 eyeBlink가 1일때는 눈감은 상태이니까

 

scale.z = 1 - eyeBlink  <- 이렇게 값을 업데이트 시켜줍니다.

 

 

 

최종코드는 이렇게 되겠습니다-!

 

 

 

 

import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController {
@IBOutlet var sceneView: ARSCNView!
var contentNode: SCNNode?
lazy var eyeLeftNode = contentNode?.childNode(withName: "eyeLeft", recursively: true)
lazy var eyeRightNode = contentNode?.childNode(withName: "eyeRight", recursively: true)
override func viewDidLoad() {
super.viewDidLoad()
setupSceneView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
resetTracking()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
private func setupSceneView() {
sceneView.delegate = self
}
private func resetTracking() {
let configuration = ARFaceTrackingConfiguration()
sceneView.session.run(configuration,
options: [.resetTracking, .removeExistingAnchors])
}
}
extension ViewController: ARSCNViewDelegate {
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
guard anchor is ARFaceAnchor else { return nil }
let resourceName = "robotHead"
self.contentNode = SCNReferenceNode(named: resourceName)
return contentNode
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else { return }
let blendShapes = faceAnchor.blendShapes
if let eyeBlinkLeft = blendShapes[.eyeBlinkLeft] as? Float, let eyeBlinkRight = blendShapes[.eyeBlinkRight] as? Float {
eyeLeftNode?.scale.z = 1 - eyeBlinkLeft
eyeRightNode?.scale.z = 1 - eyeBlinkRight
}
}
}

 

 

 

 

(참고로 애플예제를 보면 턱 트래킹(jaw tracking) 도 되어있습니다)

 

반응형
댓글

eungding님의
글이 좋았다면 응원을 보내주세요!