iOS ARKit 튜토리얼: 맨손으로 허공에 그리기

게시 됨: 2022-03-11

최근 Apple은 ARKit이라는 새로운 증강 현실(AR) 라이브러리를 발표했습니다. 많은 사람들에게 그것은 단지 또 다른 좋은 AR 라이브러리처럼 보였고, 신경써야 할 기술 파괴자가 아닙니다. 그러나 지난 몇 년 동안 AR의 진행 상황을 살펴보면 그러한 결론을 내리는 데 너무 성급해서는 안됩니다.

ARKit 튜토리얼 일러스트레이션: iOS ARKit 앱에서 가상 객체와 상호작용

이 게시물에서는 iOS ARKit을 사용하여 재미있는 ARKit 예제 프로젝트를 만들 것입니다. 사용자는 펜을 잡고 있는 것처럼 테이블 위에 손가락을 놓고 썸네일을 탭한 다음 그리기를 시작합니다. 완료되면 아래 애니메이션과 같이 사용자가 드로잉을 3D 개체로 변환할 수 있습니다. iOS ARKit 예제의 전체 소스 코드는 GitHub에서 사용할 수 있습니다.

iOS ARKit 샘플 증강 현실 앱 사용 시연

지금 iOS ARKit에 관심을 가져야 하는 이유는 무엇입니까?

숙련된 개발자라면 누구나 AR이 오래된 개념이라는 사실을 알고 있을 것입니다. AR의 첫 번째 진지한 개발은 개발자가 웹캠에서 개별 프레임에 액세스할 수 있었던 때까지로 고정할 수 있습니다. 그 당시 앱은 일반적으로 얼굴을 변형하는 데 사용되었습니다. 그러나 인류는 얼굴을 토끼로 바꾸는 것이 가장 시급한 요구 사항 중 하나가 아니라는 것을 깨닫는 데 오래 걸리지 않았고 곧 과대 광고가 사라졌습니다!

AR은 유용성과 몰입감이라는 두 가지 핵심 기술 도약을 항상 놓치고 있다고 생각합니다. 다른 AR 과대 광고를 추적한 경우 이를 알 수 있습니다. 예를 들어, AR 광고는 개발자가 모바일 카메라의 개별 프레임에 액세스할 수 있게 되면서 다시 시작되었습니다. 위대한 버니 트랜스포머의 강력한 복귀와 함께 우리는 인쇄된 QR 코드에 3D 개체를 떨어뜨리는 앱의 물결을 보았습니다. 그러나 그들은 결코 개념으로 이륙하지 못했습니다. 증강현실이 아니라 증강된 QR코드였다.

그런 다음 Google은 공상 과학 소설인 Google Glass로 우리를 놀라게 했습니다. 2년이 지났고 이 놀라운 제품이 출시될 것으로 예상되었을 때는 이미 죽은 상태였습니다! 많은 비평가들은 구글 글래스의 실패 원인을 분석하며 사회적인 측면부터 제품 출시에 대한 구글의 둔한 접근 방식에 이르기까지 모든 것을 비난했습니다. 그러나 우리는 이 기사에서 한 가지 특별한 이유, 즉 환경에 대한 몰입을 중요하게 생각합니다. Google Glass가 사용성 문제를 해결했지만 여전히 허공에 그려진 2D 이미지에 불과했습니다.

Microsoft, Facebook 및 Apple과 같은 기술 거물들은 이 가혹한 교훈을 가슴으로 배웠습니다. 2017년 6월, Apple은 몰입감을 최우선으로 하는 아름다운 iOS ARKit 라이브러리를 발표했습니다. 휴대전화를 들고 있는 것은 여전히 ​​사용자 경험을 방해하는 큰 장애물이지만 Google Glass의 교훈은 하드웨어가 문제가 아님을 알려줍니다.

나는 우리가 곧 새로운 AR 과대 광고 피크를 향해 가고 있다고 생각하며, 이 새로운 중요한 중심점을 통해 결국 자국 시장을 찾아 더 많은 AR 앱 개발이 주류가 될 수 있을 것입니다. 이것은 또한 모든 증강 현실 앱 개발 회사가 Apple의 생태계와 사용자 기반을 활용할 수 있음을 의미합니다.

하지만 역사가 충분하므로 코드로 손을 더럽히고 Apple 증강 현실이 작동하는 모습을 봅시다!

ARKit 몰입 기능

ARKit은 두 가지 주요 기능을 제공합니다. 첫 번째는 3D 공간에서의 카메라 위치이고 두 번째는 수평면 감지입니다. 전자를 달성하기 위해 ARKit은 휴대전화가 실제 3D 공간에서 움직이는 카메라라고 가정하여 어떤 지점에 3D 가상 물체를 떨어뜨리면 실제 3D 공간의 해당 지점에 고정됩니다. 그리고 후자에게 ARKit은 테이블과 같은 수평면을 감지하여 그 위에 물건을 놓을 수 있습니다.

그러면 ARKit은 이것을 어떻게 달성합니까? 이것은 VIO(Visual Inertial Odometry)라는 기술을 통해 수행됩니다. 걱정하지 마세요. 기업가들이 창업 이름 뒤에 숨은 출처를 알아낼 때 낄낄거리는 웃음의 수에서 기쁨을 찾는 것처럼 연구원들은 회사 이름 뒤에 나오는 단어를 해독하려고 할 때 머리를 긁는 횟수에서 기쁨을 찾습니다. 그들의 발명품에 이름을 붙이기 - 그래서 그들이 재미를 느끼고 계속 나아갈 수 있도록 합시다.

VIO는 카메라 프레임과 모션 센서를 융합하여 3D 공간에서 장치의 위치를 ​​추적하는 기술입니다. 카메라 프레임에서 움직임을 추적하는 것은 특징, 즉 파란색 꽃병과 흰색 테이블 사이의 가장자리와 같이 대비가 높은 이미지의 가장자리 지점을 감지하여 수행됩니다. 이러한 점이 한 프레임에서 다른 프레임으로 서로에 대해 얼마나 많이 이동했는지 감지하여 장치가 3D 공간에서 어디에 있는지 추정할 수 있습니다. 이것이 ARKit이 특징이 없는 흰색 벽을 향하여 배치되거나 장치가 매우 빠르게 움직여 이미지가 흐려지는 경우 제대로 작동하지 않는 이유입니다.

iOS에서 ARKit 시작하기

이 기사를 작성하는 시점에서 ARKit은 아직 베타 버전인 iOS 11의 일부입니다. 따라서 시작하려면 iPhone 6s 이상에서 iOS 11 베타와 새로운 Xcode 베타를 다운로드해야 합니다. New > Project > Augmented Reality App 에서 새로운 ARKit 프로젝트를 시작할 수 있습니다. 그러나 몇 가지 필수 코드 블록을 제공하고 평면 감지에 특히 유용한 공식 Apple ARKit 샘플을 사용하여 이 증강 현실 자습서를 시작하는 것이 더 편리하다는 것을 알았습니다. 따라서 이 예제 코드로 시작하여 주요 사항을 먼저 설명한 다음 프로젝트에 맞게 수정해 보겠습니다.

먼저 어떤 엔진을 사용할지 결정해야 합니다. ARKit은 Sprite SceneKit 또는 Metal과 함께 사용할 수 있습니다. Apple ARKit 예제에서는 Apple에서 제공하는 3D 엔진인 iOS SceneKit을 사용하고 있습니다. 다음으로 3D 개체를 렌더링할 보기를 설정해야 합니다. 이는 ARSCNView 유형의 보기를 추가하여 수행됩니다.

ARSCNView 는 SCNView라는 SCNView 기본 보기의 하위 클래스이지만 몇 가지 유용한 기능으로 보기를 확장합니다. 장치 카메라의 라이브 비디오 피드를 장면 배경으로 렌더링하는 동안 장치가 이 세계에서 움직이는 카메라라고 가정할 때 SceneKit 공간을 실제 세계와 자동으로 일치시킵니다.

ARSCNView 는 자체적으로 AR 처리를 수행하지 않지만 장치 카메라 및 모션 처리를 관리하는 AR 세션 개체가 필요합니다. 따라서 시작하려면 새 세션을 할당해야 합니다.

 self.session = ARSession() sceneView.session = session sceneView.delegate = self setupFocusSquare()

위의 마지막 줄은 사용자가 비행기 감지 상태를 시각적으로 설명하는 데 도움이 되는 시각적 표시기를 추가합니다. Focus Square는 ARKit 라이브러리가 아닌 샘플 코드에서 제공되며 이것이 우리가 이 샘플 코드를 시작한 주된 이유 중 하나입니다. 샘플 코드에 포함된 추가 정보 파일에서 자세한 내용을 찾을 수 있습니다. 다음 이미지는 테이블에 투영된 초점 사각형을 보여줍니다.

Apple ARKit을 사용하여 테이블에 투영된 초점 사각형

다음 단계는 ARKit 세션을 시작하는 것입니다. 사용자를 더 이상 추적하지 않으면 이전 세션 정보를 사용할 수 없으므로 보기가 나타날 때마다 세션을 다시 시작하는 것이 좋습니다. 따라서 viewDidAppear에서 세션을 시작하겠습니다.

 override func viewDidAppear(_ animated: Bool) { let configuration = ARWorldTrackingSessionConfiguration() configuration.planeDetection = .horizontal session.run(configuration, options: [.resetTracking, .removeExistingAnchors]) }

위의 코드에서는 ARKit 세션 구성을 설정하여 수평면을 감지하는 것으로 시작합니다. 이 기사를 작성하는 현재 Apple은 이 외에 다른 옵션을 제공하지 않습니다. 그러나 분명히 이것은 미래에 더 복잡한 물체를 감지하는 것을 암시합니다. 그런 다음 세션 실행을 시작하고 추적을 재설정했는지 확인합니다.

마지막으로 카메라 위치, 즉 실제 장치 방향이나 위치가 변경될 때마다 Focus Square를 업데이트해야 합니다. 이것은 3D 엔진의 새 프레임이 렌더링될 때마다 호출되는 SCNView의 렌더러 대리자 함수에서 수행할 수 있습니다.

 func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { updateFocusSquare() }

이 시점에서 앱을 실행하면 수평면을 검색하는 카메라 스트림 위에 초점 사각형이 표시되어야 합니다. 다음 섹션에서는 평면을 감지하는 방법과 그에 따라 초점 사각형을 배치하는 방법을 설명합니다.

ARKit에서 평면 감지

ARKit은 새로운 비행기를 감지하거나 기존 비행기를 업데이트하거나 제거할 수 있습니다. 평면을 편리한 방식으로 처리하기 위해 평면 위치 정보와 초점 사각형에 대한 참조를 보유하는 더미 SceneKit 노드를 생성합니다. 평면은 X 및 Z 방향으로 정의됩니다. 여기서 Y는 표면의 법선입니다. 즉, 평면에 인쇄된 것처럼 보이게 하려면 평면의 동일한 Y 값 내에서 도면 노드 위치를 항상 유지해야 합니다. .

평면 감지는 ARKit에서 제공하는 콜백 함수를 통해 수행됩니다. 예를 들어 다음 콜백 함수는 새 평면이 감지될 때마다 호출됩니다.

 var planes = [ARPlaneAnchor: Plane]() func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { if let planeAnchor = anchor as? ARPlaneAnchor { serialQueue.async { self.addPlane(node: node, anchor: planeAnchor) self.virtualObjectManager.checkIfObjectShouldMoveOntoPlane(anchor: planeAnchor, planeAnchorNode: node) } } } func addPlane(node: SCNNode, anchor: ARPlaneAnchor) { let plane = Plane(anchor) planes[anchor] = plane node.addChildNode(plane) } ... class Plane: SCNNode { var anchor: ARPlaneAnchor var focusSquare: FocusSquare? init(_ anchor: ARPlaneAnchor) { self.anchor = anchor super.init() } ... }

콜백 함수는 anchornode 라는 두 개의 매개변수를 제공합니다. node 는 평면의 정확한 위치와 방향에 배치된 일반 SceneKit 노드입니다. 기하학이 없으므로 보이지 않습니다. 우리는 그것을 사용하여 우리 자신의 평면 노드를 추가합니다. 이 노드는 또한 보이지 않지만 anchor 에 평면 방향과 위치에 대한 정보를 보유합니다.

그렇다면 위치와 방향은 ARPlaneAnchor 에 어떻게 저장됩니까? 위치, 방향 및 크기는 모두 4x4 매트릭스로 인코딩됩니다. 제가 여러분이 배울 수학 개념을 하나 선택할 기회가 있다면 그것은 의심할 여지 없이 행렬일 것입니다. 어쨌든, 우리는 이 4x4 행렬을 다음과 같이 설명함으로써 이것을 우회할 수 있습니다. 4x4 부동 소수점 숫자를 포함하는 화려한 2차원 배열. 이 숫자에 로컬 공간의 3D 정점 v1을 특정 방식으로 곱하면 월드 공간에서 v1을 나타내는 새로운 3D 정점 v2가 생성됩니다. 따라서 로컬 공간에서 v1 = (1, 0, 0)이고 월드 공간에서 x = 100에 배치하려는 경우 v2는 월드 공간과 관련하여 (101, 0, 0)과 같습니다. 물론 축에 대한 회전을 추가하면 이에 대한 수학이 더 복잡해 지지만 좋은 소식은 우리가 그것을 이해하지 않고도 할 수 있다는 것입니다(이 개념에 대한 자세한 설명은 이 훌륭한 기사의 관련 섹션을 확인하는 것이 좋습니다. ).

checkIfObjectShouldMoveOntoPlane 은 이미 그려진 객체가 있는지 확인하고 이러한 모든 객체의 y축이 새로 감지된 평면의 y축과 일치하는지 확인합니다.

이제 이전 섹션에서 설명한 updateFocusSquare() 로 돌아갑니다. 초점을 화면 중앙에 정사각형으로 유지하고 가장 가까운 감지된 평면에 투영하고 싶습니다. 아래 코드는 이를 보여줍니다.

 func updateFocusSquare() { let worldPos = worldPositionFromScreenPosition(screenCenter, self.sceneView) self.focusSquare?.simdPosition = worldPos } func worldPositionFromScreenPosition(_ position: CGPoint, in sceneView: ARSCNView) -> float3? { let planeHitTestResults = sceneView.hitTest(position, types: .existingPlaneUsingExtent) if let result = planeHitTestResults.first { return result.worldTransform.translation } return nil }

sceneView.hitTest 는 이 2D 점을 가장 가까운 평면 아래에 투영하여 화면 보기의 2D 점에 해당하는 실제 평면을 검색합니다. result.worldTransform 은 감지된 평면의 모든 변환 정보를 보유하는 4x4 행렬이고 result.worldTransform.translation 은 위치만 반환하는 편리한 함수입니다.

이제 화면의 2D 포인트가 주어진 감지된 표면에 3D 개체를 떨어뜨리는 데 필요한 모든 정보가 있습니다. 자, 그림을 시작해 봅시다.

그림

먼저 컴퓨터 비전에서 사람의 손가락을 따라 모양을 그리는 접근 방식을 설명하겠습니다. 도형 그리기는 움직이는 손가락의 모든 새 위치를 감지하고 해당 위치에 정점을 놓고 각 정점을 이전 정점과 연결하여 수행됩니다. 정점은 단순한 선으로 연결하거나 부드러운 출력이 필요한 경우 베지어 곡선을 통해 연결할 수 있습니다.

간단하게 하기 위해 우리는 약간의 순진한 접근 방식을 따를 것입니다. 손가락의 모든 새로운 위치에 대해 감지된 평면에 모서리가 둥글고 높이가 거의 0인 매우 작은 상자를 드롭합니다. 마치 점처럼 보일 것입니다. 사용자가 그리기를 마치고 3D 버튼을 선택하면 사용자의 손가락 움직임에 따라 드롭된 모든 개체의 높이가 변경됩니다.

다음 코드는 점을 나타내는 PointNode 클래스를 보여줍니다.

 let POINT_SIZE = CGFloat(0.003) let POINT_HEIGHT = CGFloat(0.00001) class PointNode: SCNNode { static var boxGeo: SCNBox? override init() { super.init() if PointNode.boxGeo == nil { PointNode.boxGeo = SCNBox(width: POINT_SIZE, height: POINT_HEIGHT, length: POINT_SIZE, chamferRadius: 0.001) // Setup the material of the point let material = PointNode.boxGeo!.firstMaterial material?.lightingModel = SCNMaterial.LightingModel.blinn material?.diffuse.contents = UIImage(named: "wood-diffuse.jpg") material?.normal.contents = UIImage(named: "wood-normal.png") material?.specular.contents = UIImage(named: "wood-specular.jpg") } let object = SCNNode(geometry: PointNode.boxGeo!) object.transform = SCNMatrix4MakeTranslation(0.0, Float(POINT_HEIGHT) / 2.0, 0.0) self.addChildNode(object) } . . . }

위의 코드에서 y축을 따라 지오메트리를 높이의 절반으로 변환하는 것을 알 수 있습니다. 그 이유는 객체의 바닥이 항상 y = 0 에 있도록 하여 평면 위에 나타나도록 하기 위한 것입니다.

다음으로 SceneKit의 렌더러 콜백 함수에서 동일한 PointNode 클래스를 사용하여 펜촉처럼 작동하는 표시기를 그립니다. 드로잉이 활성화된 경우 해당 위치에 점을 드롭하고 3D 모드가 활성화된 경우 드로잉을 3D 구조로 올립니다.

 func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { updateFocusSquare() // Setup a dot that represents the virtual pen's tippoint if (self.virtualPenTip == nil) { self.virtualPenTip = PointNode(color: UIColor.red) self.sceneView.scene.rootNode.addChildNode(self.virtualPenTip!) } // Draw if let screenCenterInWorld = worldPositionFromScreenPosition(self.screenCenter, self.sceneView) { // Update virtual pen position self.virtualPenTip?.isHidden = false self.virtualPenTip?.simdPosition = screenCenterInWorld // Draw new point if (self.inDrawMode && !self.virtualObjectManager.pointNodeExistAt(pos: screenCenterInWorld)){ let newPoint = PointNode() self.sceneView.scene.rootNode.addChildNode(newPoint) self.virtualObjectManager.loadVirtualObject(newPoint, to: screenCenterInWorld) } // Convert drawing to 3D if (self.in3DMode ) { if self.trackImageInitialOrigin != nil { DispatchQueue.main.async { let newH = 0.4 * (self.trackImageInitialOrigin!.y - screenCenterInWorld.y) / self.sceneView.frame.height self.virtualObjectManager.setNewHeight(newHeight: newH) } } else { self.trackImageInitialOrigin = screenCenterInWorld } } }

virtualObjectManager 는 그려진 점을 관리하는 클래스입니다. 3D 모드에서는 마지막 위치와의 차이를 추정하고 그 값으로 모든 포인트의 높이를 높이거나 낮춥니다.

지금까지는 가상 펜이 화면 중앙에 있다고 가정하고 감지된 표면에 그림을 그리고 있습니다. 이제 재미있는 부분은 사용자의 손가락을 감지하고 화면 중앙 대신 사용하는 것입니다.

사용자의 손가락 끝 감지

Apple이 iOS 11에 도입한 멋진 라이브러리 중 하나는 Vision Framework입니다. 그것은 꽤 편리하고 효율적인 방법으로 몇 가지 컴퓨터 비전 기술을 제공합니다. 특히, 증강 현실 튜토리얼에서 객체 추적 기술을 사용할 것입니다. 객체 추적은 다음과 같이 작동합니다. 먼저 추적하려는 객체의 이미지 경계 내에서 정사각형의 좌표와 이미지를 제공합니다. 그런 다음 추적을 초기화하는 몇 가지 함수를 호출합니다. 마지막으로 해당 객체의 위치가 변경된 새 이미지와 이전 작업의 분석 결과를 입력합니다. 이를 감안할 때 객체의 새 위치가 반환됩니다.

우리는 작은 트릭을 사용할 것입니다. 우리는 사용자에게 펜을 잡고 있는 것처럼 테이블에 손을 대고 썸네일이 카메라를 향하도록 한 다음 화면의 썸네일을 탭해야 합니다. 여기서 자세히 설명해야 할 두 가지 사항이 있습니다. 먼저 썸네일에는 흰색 썸네일, 스킨, 테이블 간의 대비를 통해 추적할 수 있는 고유한 기능이 충분해야 합니다. 이것은 더 어두운 피부 색소가 더 안정적인 추적을 초래한다는 것을 의미합니다. 둘째, 사용자가 테이블에 손을 대고 있고 이미 테이블을 평면으로 감지하고 있기 때문에 2D 보기에서 3D 환경으로 축소판 위치를 투영하면 손가락의 위치가 거의 정확한 결과가 됩니다. 테이블.

다음 이미지는 Vision 라이브러리에서 감지할 수 있는 특징점을 보여줍니다.

Vision 라이브러리에서 감지한 iOS ARKit 기능 포인트

다음과 같이 탭 제스처에서 썸네일 추적을 초기화합니다.

 // MARK: Object tracking fileprivate var lastObservation: VNDetectedObjectObservation? var trackImageBoundingBox: CGRect? let trackImageSize = CGFloat(20) @objc private func tapAction(recognizer: UITapGestureRecognizer) { lastObservation = nil let tapLocation = recognizer.location(in: view) // Set up the rect in the image in view coordinate space that we will track let trackImageBoundingBoxOrigin = CGPoint(x: tapLocation.x - trackImageSize / 2, y: tapLocation.y - trackImageSize / 2) trackImageBoundingBox = CGRect(origin: trackImageBoundingBoxOrigin, size: CGSize(width: trackImageSize, height: trackImageSize)) let t = CGAffineTransform(scaleX: 1.0 / self.view.frame.size.width, y: 1.0 / self.view.frame.size.height) let normalizedTrackImageBoundingBox = trackImageBoundingBox!.applying(t) // Transfrom the rect from view space to image space guard let fromViewToCameraImageTransform = self.sceneView.session.currentFrame?.displayTransform(withViewportSize: self.sceneView.frame.size, orientation: UIInterfaceOrientation.portrait).inverted() else { return } var trackImageBoundingBoxInImage = normalizedTrackImageBoundingBox.applying(fromViewToCameraImageTransform) trackImageBoundingBoxInImage.origin.y = 1 - trackImageBoundingBoxInImage.origin.y // Image space uses bottom left as origin while view space uses top left lastObservation = VNDetectedObjectObservation(boundingBox: trackImageBoundingBoxInImage) }

위의 가장 까다로운 부분은 탭 위치를 UIView 좌표 공간에서 이미지 좌표 공간으로 변환하는 방법입니다. ARKit은 이미지 좌표 공간에서 뷰포트 좌표 공간으로 변환하지만 그 반대는 아닌 displayTransform 매트릭스를 제공합니다. 그럼 역함수는 어떻게 할 수 있을까요? 역행렬을 사용합니다. 이번 포스트에서는 정말 수학의 사용을 최소화하려고 노력했지만, 3D 세계에서는 어쩔 수 없는 경우가 있습니다.

다음으로 렌더러에서 손가락의 새 위치를 추적하기 위해 새 이미지를 입력합니다.

 func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { // Track the thumbnail guard let pixelBuffer = self.sceneView.session.currentFrame?.capturedImage, let observation = self.lastObservation else { return } let request = VNTrackObjectRequest(detectedObjectObservation: observation) { [unowned self] request, error in self.handle(request, error: error) } request.trackingLevel = .accurate do { try self.handler.perform([request], on: pixelBuffer) } catch { print(error) } . . . }

객체 추적이 완료되면 썸네일 위치를 업데이트하는 콜백 함수를 호출합니다. 일반적으로 탭 인식기에 작성된 코드의 역수입니다.

 fileprivate func handle(_ request: VNRequest, error: Error?) { DispatchQueue.main.async { guard let newObservation = request.results?.first as? VNDetectedObjectObservation else { return } self.lastObservation = newObservation var trackImageBoundingBoxInImage = newObservation.boundingBox // Transfrom the rect from image space to view space trackImageBoundingBoxInImage.origin.y = 1 - trackImageBoundingBoxInImage.origin.y guard let fromCameraImageToViewTransform = self.sceneView.session.currentFrame?.displayTransform(withViewportSize: self.sceneView.frame.size, orientation: UIInterfaceOrientation.portrait) else { return } let normalizedTrackImageBoundingBox = trackImageBoundingBoxInImage.applying(fromCameraImageToViewTransform) let t = CGAffineTransform(scaleX: self.view.frame.size.width, y: self.view.frame.size.height) let unnormalizedTrackImageBoundingBox = normalizedTrackImageBoundingBox.applying(t) self.trackImageBoundingBox = unnormalizedTrackImageBoundingBox // Get the projection if the location of the tracked image from image space to the nearest detected plane if let trackImageOrigin = self.trackImageBoundingBox?.origin { self.lastFingerWorldPos = self.virtualObjectManager.worldPositionFromScreenPosition(CGPoint(x: trackImageOrigin.x - 20.0, y: trackImageOrigin.y + 40.0), in: self.sceneView) } } }

마지막으로 그림을 그릴 때 화면 중앙 대신 self.lastFingerWorldPos 를 사용하면 끝입니다.

ARKit과 미래

이 게시물에서는 AR이 사용자 손가락 및 실제 테이블과의 상호 작용을 통해 어떻게 몰입할 수 있는지 보여주었습니다. 컴퓨터 비전의 더 많은 발전과 가제트(예: 깊이 카메라)에 AR 친화적인 하드웨어를 추가함으로써 우리는 우리 주변의 점점 더 많은 물체의 3D 구조에 액세스할 수 있습니다.

아직 대중에게 공개되지는 않았지만 Microsoft가 AR 맞춤형 하드웨어와 고급 3D 환경 인식 기술을 결합한 Hololens 장치를 통해 AR 경쟁에서 승리하는 데 얼마나 진지한지를 언급할 가치가 있습니다. 누가 이 경주에서 승리할지 기다리거나 지금 실제 몰입형 증강 현실 앱을 개발하여 경주에 참여할 수 있습니다! 그러나 제발, 인류에게 호의를 베풀고 살아있는 물체를 토끼로 바꾸지 마십시오.