Mục đích:

  • Làm quen với ARKit sử dụng SceneKit

  • Hiểu cách ARKit hoạt động với các đối tượng 3D

 

Chuẩn bị:

  • Thiếu bị sử dụng chíp A9 trở lên iphone 6s trở lên.

  • Tạo mới project

  • Setting ARKit, SceneKit

  • Kết nối ARSCNView vào ViewController

  • Cấu hình Camera

  • Thêm đối tượng 3D vào ARSCNView

  • Thêm gesture recognizer vào ARSCNView

  • Thêm, Xoá các đối tượng từ ARSCNView

 

Tạo mới project việc này chắc các bạn đã quen rồi, mình sẽ vào luôn phần add ARKit

  • Đầu tiền các bạn mở Main.storyboard, nhìn vào phần các components gõ ARKit Scenekit

Kết nối ARKit vào ViewController: Đầu tiên các bạn cần import ARKit, sau đó kéo đối tượng vào như bình thường và đặt tên sceneView.

import ARKit

 

Cấu hình ARSCNView Session

  • ARKit đã hỗ trợ luôn cho chúng ta phần camera là giao diện mặc định và chúng ta sẽ thực hiện luôn các phần về nhận diện các đối tượng trên đó. Ở dưới đây là đoạn mã mình cấu hình:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let configuration = ARWorldTrackingConfiguration()
    sceneView.session.run(configuration)
}

 

  • Ở đây tôi gọi đến đối tượng ARWorlTrackingConfigutation, ở đây world tracking là gì? theo tài liệu apple cung cấp thì đối tượng này cung cấp cho chúng ta theo dõi đối tượng theo 6 cấp độ, tìm ra các điểm nhỏ, phần tích mặt phẳng,… chúng ta có thể dừng quá trình hoặc bật lại chức năng nhận diện này tuỳ ý.

  • Như tôi đã nói ở trên thì chúng ta có thể tạm dừng chức năng nhận diện này, ở dưới đây khi mà viewcontroller biết mất tôi sẽ dừng nó như sau:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    sceneView.session.pause()
}

 

 

Tiếp theo sẽ đến phần cấp quyền truy cập và camera

  • Trước khi chạy app chúng ta cần thông báo cho người dùng biết rằng sẽ sử dụng đến camera(từ ios10 thì Apple yêu cầu nhé). Các bạn set key: Privary-Camera Usage Description với giá trị là gì cũng đc.

  • Sau khi bạn chạy thì nó sẽ popup ra hỏi ở đây các bạn nhớ ấn OK nhé.

 

 

Thêm đối tượng 3D vào ARSCNView

Tối sẽ thêm func sau:

func addBox() {
    let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(0, 0, -0.2)
    
    let scene = SCNScene()
    scene.rootNode.addChildNode(boxNode)
    sceneView.scene = scene
}

Với đối tượng “box” 1 Float = 1 mét

Sau khi tạo một node, node này tượng trưng cho vị trí, toạ độ của một đối tượng nhưng nó lại không có nội dung.

Vậy để cho node có thể hiển thị nội dung thì chúng ta cần định dạng loại hình dạng(getmetry) cho nó, và tiếp theo là vị trí 0, 0, -0.2. Ở đây 0.2 là trục z, 0,2 thì nó sẽ hướng gần camera 0.2 mét.

Tiếp theo đơn giản bạn cần gọi func vừa tạo.

override func viewDidLoad() {
    super.viewDidLoad()
    addBox()
}

Đến đây bạn có thể chạy thử:

 

Bạn hoàn toàn có thể viết lại như sau:

func addBox() {
    let box = SCNBox(width: 0.05, height: 0.05, length: 0.05, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(0, 0, -0.2)
    
    sceneView.scene.rootNode.addChildNode(boxNode)
}

 

Tiếp theo đến phần thêm gesture recognizer vào ARSCNView

func addTapGestureToSceneView() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.didTap(withGestureRecognizer:)))
    sceneView.addGestureRecognizer(tapGestureRecognizer)
}

Ở đây tôi tạo một tap gesture, với target của nó là didTap.

 

Xoá đối tượng từ ARSCNView

@objc func didTap(withGestureRecognizer recognizer: UIGestureRecognizer) {
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation)
    guard let node = hitTestResults.first?.node else { return }
    node.removeFromParentNode()
}

 

ở đây đơn giản tôi lấy ra toạ độ người dùng tap sau đó lấy ra đối tượng và xoá.

 

Các bạn nhớ gọi AddTapGestureToSceneView()

 

override func viewDidLoad() {
    super.viewDidLoad()
    
    addBox()
    addTapGestureToSceneView()
}

 

Bây giờ bạn hãy build vào tử xem khi tap vào note thi nó có được xoá hay không.

 

Thêm nhiều đối tượng

Để thuận tiện cho việc thêm nhiều đối tượng thì chúng ta cần viết 1 func convert float4x4 thành float3

extension float4x4 {
    var translation: float3 {
        let translation = self.columns.3
        return float3(translation.x, translation.y, translation.z)
    }
}

Tiếp theo chúng ta chỉnh lại addBox func như sau:

 

func addBox(x: Float = 0, y: Float = 0, z: Float = -0.2) {
    let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
    
    let boxNode = SCNNode()
    boxNode.geometry = box
    boxNode.position = SCNVector3(x, y, z)
    
    sceneView.scene.rootNode.addChildNode(boxNode)
}

 

Ở đây chúng ta thêm các tham số vào hàm addBox default của các tham số thì vẫn như cũ.

 

Bây giờ chúng ta sẽ chỉnh lại hàm didTap, ở đây sẽ thêm đối tượng tại ví trí chúng ta tap.

let hitTestResultsWithFeaturePoints = sceneView.hitTest(tapLocation, types: .featurePoint)
 
if let hitTestResultWithFeaturePoints = hitTestResultsWithFeaturePoints.first {
    let translation = hitTestResultWithFeaturePoints.worldTransform.translation
    addBox(x: translation.x, y: translation.y, z: translation.z)
}

 

Tiếp theo chúng ta sẽ thêm logic khi add đối tượng mới, tôi sẽ check nếu không tồn tại đối tượng nào tại vị trí tap thì sẽ add, còn ngược lại thì sẽ xoá đối tượng đó đi, ở đây cõ đoạn mã convert  float4x4 thành float3 các bạn chú ý ở phần trên cũng ta đã viết extension rồi nhé.

@objc func didTap(withGestureRecognizer recognizer: UIGestureRecognizer) {
    let tapLocation = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(tapLocation)
    guard let node = hitTestResults.first?.node else {
        let hitTestResultsWithFeaturePoints = sceneView.hitTest(tapLocation, types: .featurePoint)
        if let hitTestResultWithFeaturePoints = hitTestResultsWithFeaturePoints.first {
            let translation = hitTestResultWithFeaturePoints.worldTransform.translation
            addBox(x: translation.x, y: translation.y, z: translation.z)
        }
        return
    }
    node.removeFromParentNode()
}

 

Giờ các bạn có thể chạy demo để xem nó hoạt động như nào, cảm ơn vì đã đọc.

Source code:https://github.com/tubeobeotu/Swift-Sample/tree/master/ARKitDemo

Khóa học lập trình di động tại Techmaster:

Để cài đặt MacOSX lên phần cứng không phải Apple liên hệ chuyên gia cài Hackintosh:

  • Nguyễn Minh Sơn: 01287065634
  • Huỳnh Minh Sơn: 0936225565
  • Website: caidatmacos.com