Danny의 iOS 컨닝페이퍼
article thumbnail
반응형

1. 시작

오늘은 SceneKit으로 카메라를 통한 줄자를 만들어 보겠습니다.

 

간단히 설명할 예정이라 자세한 내용은 이전 글을 참고하시길 바랍니다.

SceneKit의 사용법 (1) - 정육면체와 달을 만들어 보자

SceneKit의 사용법 (2) - 주사위 만들기

 

2. 화면의 위치 얻기

touchesBegan 메서드를 통하여 터치한 화면(2D 공간)에서 실제 카메라에 비치는(3D 공간) 좌표를 구해봅시다.

 

raycastQuery를 통하여 터치 시 그 공간 좌표정보를 요청한 뒤,

raycast로 만든 쿼리값(좌표정보 요청)을 넣어준 뒤 결괏값으로 변환시켜서 좌표 정보를 얻을 수 있습니다.

<swift>
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { resetDot() guard let touch = touches.first else { return } // 터치되는 위치 얻기 let touchLocation = touch.location(in: sceneView) // 2D공간(화면)을 3D로 좌표를 계산하여 변환시켜 준다. guard let query = sceneView.raycastQuery(from: touchLocation, allowing: .existingPlaneGeometry, alignment: .any) else { return } // 터치시 3D공간의 위치 정보 결과들 (return = [ARRaycastResult]) let hitResults = sceneView.session.raycast(query) // 터치시 3D공간의 위치결과 guard let hitResult = hitResults.first else { return } // 점을 추가하기 addDot(at: hitResult) }

여기서 resetDot() , addDot(at:)는 코드 정리를 위해 따로 묶어놓았습니다. 바로 밑에서 설명드리겠습니다.

 

3. 점 만들기

위에 공간 좌표를 얻었으면 이제 터치한 지점에 점을 생성시켜 봅시다.

 

터치한 위치(hitResult)의 리턴값이 ARRaycastResult 이므로 이 위치를 받아서 점을 생성시킵니다.

 

ARKit의 형상 생성법을 모르신다면 SceneKit의 사용법 (1) - 정육면체와 달을 만들어 보자 를 참고하세요

<swift>
func addDot(at location: ARRaycastResult) { let dotGeometry = SCNSphere(radius: 0.002) let material = SCNMaterial() material.diffuse.contents = UIColor.red dotGeometry.materials = [material] let dotNode = SCNNode() dotNode.geometry = dotGeometry dotNode.position = SCNVector3(location.worldTransform.columns.3.x, location.worldTransform.columns.3.y, location.worldTransform.columns.3.z) sceneView.scene.rootNode.addChildNode(dotNode) // 나중에 초기화 시킬 때 사용하려고 전역변수에 담았습니다. dotNodes.append(dotNode) // 점을 두번 찍으면 거리를 계산하기. if dotNodes.count >= 2 { calculate() } }

또한 계산 및 리셋을 위해 전역변수를 만들어 줍시다.

<swift>
var dotNodes = [SCNNode]()

 

4. 계산하기

가장 중요한 두 점 사이를 계산해주는 함수를 만들어야 합니다.

 

그전에 우리는 수학 공부를 간단히 해봅시다.......

 

자 다들 피타고라스의 정리에 대해서 들어보셨을 겁니다.

2차원으로 된 두 점 사이의 거리는 아마 다들 구하실 수 있을 거예요. 

 

그런데 우리는 3차원의 두 점 사이의 거리를 구해야 됩니다. 점의 생성 좌표가 3차원이기 때문이죠.

 

그림을 보면서 이해해 봅시다.

3차원 공간의 두 점

 

피타고라스의 정리를 생각하며 각각의 위치를 통해 가상의 정육면체를 생성해 줍니다.

이렇게 보면 📐 ABQ가 직각삼각형이니 우리는 변 AB의 길이, 즉 두 점 사이의 거리를 구할 수 있습니다!

 

먼저 📐 APQ를 통하여 변 AQ를 구해봅시다. 

변 AQ = √ ( (변 PQ)² + (변 AP)² )

변 AQ = √ ( (x₂ - x₁)² + (y₂ - y₁)² )

 

 📐 ABQ의 밑변인 변 AQ를 구했으니 높이인 변 BQ를 갖고 바로 빗변인 변 AB를 구할 수 있습니다.

변 AB = √ ( (변 AQ)² + (변 BQ)² )

변 AB = √ ( (x₂ - x₁)² + (y₂ - y₁)² + (z₂ - z₁)² )

 

이렇게 이제 우리는 3D공간의 두 점 사이의 거리를 구할 수 있게 됐습니다.

 

바로 코드에 적용해 봅시다. 

 

일단 전역변수로 첫 번째 위치와 두 번째 위치를 갖고 온 뒤

제곱근(루트, √)sqrt 와  제곱 함수(pow) 를 사용하여 두 점 사이를 구해봅시다.

<swift>
func calculate() { let start = dotNodes[0] let end = dotNodes[1] // 그림 참고. 월드 좌표계의 두 점 사이의 거리 구하기 // sqrt 제곱근(루트, √) 만드는 함수 , pow 제곱하기 let distance = sqrtf(powf(end.position.x - start.position.x, 2) + // 변 PQ powf(end.position.y - start.position.y, 2) + // 변 AP powf(end.position.z - start.position.z, 2)) // 변 BQ // cm로 변형 let distanceUnitCm = String(format: "%.2f", distance * 100) updateText(text: distanceUnitCm + "Cm", atPosition: start.position) }

 

5. 입체 글자 생성하기

ARKit의 형상 생성법을 모르신다면 SceneKit의 사용법 (1) - 정육면체와 달을 만들어 보자 를 참고하세요

 

SCNText를 생성할 때는 Material을 따로 만들지 않아도 됩니다.

<swift>
func updateText(text: String, atPosition position: SCNVector3) { // 업데이트 될때 마다 텍스트 지우기 textNode.removeFromParentNode() // 입체감 있는 텍스트를 생성 let textGeometry = SCNText(string: text, extrusionDepth: 1.0) // material을 따로 만들지 않아도 된다. textGeometry.firstMaterial?.diffuse.contents = UIColor.red textNode = SCNNode(geometry: textGeometry) textNode.position = SCNVector3(position.x + 0.05, position.y , position.z - 0.25) // 기본 단위가 미터라서 스케일을 줄여줌. textNode.scale = SCNVector3(0.005, 0.005, 0.005) sceneView.scene.rootNode.addChildNode(textNode) }

여기도 마찬가지로 리셋을 위해서 전역변수를 만들어 줬습니다.

<swift>
var textNode = SCNNode()

 

6. 리셋시키기

마지막입니다. 지금까진 터치 시 점을 생성만 계속하게 되죠.

 

그러므로 조건을 걸어서 점이 2개 이상이면 리셋을 시켜줄 겁니다.

<swift>
func resetDot() { if dotNodes.count >= 2 { // node에서 점을 지우기 dotNodes.forEach { $0.removeFromParentNode() } // 계산을 위해 다시 초기화 dotNodes = [SCNNode]() } }

 

7. 완성

청소를 안 해서 그런지 맥북이 반짝 거리네요...

제 맥북의 길이는 30.4cm인데 테스터 결과 30.49cm!!!

거리 정확도가 꽤나 높다는 것을 알 수 있었습니다.

전체 코드를 보고 싶다면 Github 를 참고하세요.

 

 

ScnenKit의 다른 예제를 보고 싶다면 아래 링크를 참고하세요

 

[iOS/Swift] SceneKit의 사용법 (1) - 정육면체와 달을 만들어 보자

시작 AR 주사위 던지는 앱을 만들기 앞서 이해를 돕기 위해 들어가기 앞서 간단한 Cube(정육면체)와 Shpere(구)를 만들어 봅시다. 사용법 iOS -> Augmented Reality App 선택 Content Technology : SceneKit을 선택해

ios-daniel-yang.tistory.com

 

[iOS/Swift] SceneKit의 사용법 (2) - 주사위 만들기

시작 오늘은 SceneKit으로 주사위 생성 및 굴리기를 해봅시다. 순서는 이전에 만든 Cube와 달 만들기와 거의 동일하니 못 보셨다면 여기를 참고하세요. 바로 시작하겠습니다. 주사위로 사용할 모델

ios-daniel-yang.tistory.com

 

[iOS/Swift] SceneKit의 사용법 (4) - 이미지를 인식하여 3D형상 만들기

시작 오늘은 SceneKit으로 이미지를 인식하여 그 위에 캐릭터를 올려볼 예정입니다. 간단히 설명할 예정이라 자세한 내용은 이전 글을 참고하시길 바랍니다. SceneKit의 사용법 (1) - 정육면체와 달을

ios-daniel-yang.tistory.com

 

8. 참고

 

iOS & Swift - The Complete iOS App Development Bootcamp

From Beginner to iOS App Developer with Just One Course! Fully Updated with a Comprehensive Module Dedicated to SwiftUI!

www.udemy.com

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!