長方形を想定すると、水平面上にある、あなたは上のシーンに対するヒットテストを実行することができますすべての4つのコーナーを使用し、それらのコーナーの3つを使用して、長方形の幅、高さ、中心、および向きを計算します。
Iは正確にないGitHubの上で利用可能なデモアプリケーションを有する: https://github.com/mludowise/ARKitRectangleDetection
VNRectangleObservation
から矩形の角の座標が、携帯電話の回転に応じて画像のサイズ及び異なる座標における相対的であろうが。あなたは、ビューのサイズによってそれらを乗算し、携帯電話の回転に基づいてそれらを反転必要があります
func convertFromCamera(_ point: CGPoint, view sceneView: ARSCNView) -> CGPoint {
let orientation = UIApplication.shared.statusBarOrientation
switch orientation {
case .portrait, .unknown:
return CGPoint(x: point.y * sceneView.frame.width, y: point.x * sceneView.frame.height)
case .landscapeLeft:
return CGPoint(x: (1 - point.x) * sceneView.frame.width, y: point.y * sceneView.frame.height)
case .landscapeRight:
return CGPoint(x: point.x * sceneView.frame.width, y: (1 - point.y) * sceneView.frame.height)
case .portraitUpsideDown:
return CGPoint(x: (1 - point.y) * sceneView.frame.width, y: (1 - point.x) * sceneView.frame.height)
}
}
その後、あなたはすべての4頭の隅にヒットテストを実行することができます。ヒットテストを実行するときは、タイプ.existingPlaneUsingExtent
を使用して、ARKitが水平面に対してヒットを返すようにすることが重要です。
let tl = sceneView.hitTest(convertFromCamera(rectangle.topLeft, view: sceneView), types: .existingPlaneUsingExtent)
let tr = sceneView.hitTest(convertFromCamera(rectangle.topRight, view: sceneView), types: .existingPlaneUsingExtent)
let bl = sceneView.hitTest(convertFromCamera(rectangle.bottomLeft, view: sceneView), types: .existingPlaneUsingExtent)
let br = sceneView.hitTest(convertFromCamera(rectangle.bottomRight, view: sceneView), types: .existingPlaneUsingExtent)
そして、それは、各ヒットテストは、0からnまでの結果を返す可能性があるため、あなたは別の平面上に含まれている任意のヒットテストをフィルタリングする必要があります
...少し複雑になります。あなたは、各ARHitTestResult
のためのアンカーを比較することによって、これを行うことができます。
hit1.anchor == hit2.anchor
また、一つのコーナーはいずれも返さない場合、それは大丈夫ですので、あなただけの長方形の大きさ、位置、および方向を識別するために、4つの隅のうちの3を必要としますテスト結果をヒットします。私がどのようにしたかについては、hereを見てください。
左隅と右隅の間の距離(上端または下端のいずれか)から長方形の幅を計算できます。同様に、上部の&の下部コーナー(左または右のいずれか)の間の距離から矩形の高さを計算することもできます。
func distance(_ a: SCNVector3, from b: SCNVector3) -> CGFloat {
let deltaX = a.x - b.x
let deltaY = a.y - b.y
let deltaZ = a.z - b.z
return CGFloat(sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ))
}
let width = distance(right, from: left)
let height = distance(top, from: bottom)
あなたは長方形の対角(TOPLEFT & bottomRight又はtopRight & bottomLeftいずれか)から中間点を取得することにより、その位置を計算することができる:
let midX = (c1.x + c2.x)/2
let midY = (c1.y + c2.y)/2
let midZ = (c1.z + c2.z)/2
let center = SCNVector3Make(midX, midY, midZ)
あなたはまた、矩形の向きを算出することができます(y軸に沿った回転)を左右のコーナー(上または下のいずれかの方向)から選択することができる。
let distX = right.x - left.x
let distZ = right.z - left.z
let orientation = -atan(distZ/distX)
それをまとめて、AR内に何かを矩形の上に重ねて表示します。 SCNNode
をサブクラス化して仮想矩形を表示する例を示します。
class RectangleNode: SCNNode {
init(center: SCNVector3, width: CGFloat, height: CGFloat, orientation: Float) {
super.init()
// Create the 3D plane geometry with the dimensions calculated from corners
let planeGeometry = SCNPlane(width: width, height: height)
let rectNode = SCNNode(geometry: planeGeometry)
// Planes in SceneKit are vertical by default so we need to rotate
// 90 degrees to match planes in ARKit
var transform = SCNMatrix4MakeRotation(-Float.pi/2.0, 1.0, 0.0, 0.0)
// Set rotation to the corner of the rectangle
transform = SCNMatrix4Rotate(transform, orientation, 0, 1, 0)
rectNode.transform = transform
// We add the new node to ourself since we inherited from SCNNode
self.addChildNode(rectNode)
// Set position to the center of rectangle
self.position = center
}
}
これは実際に動作しますか?ビジョン観測によって返されるboundingBoxの起点とサイズは、uikit座標ではなく[0,1]の範囲にあり、hitTestはuikit座標が必要です –