ARKitのARSCNViewを使用して、iPadのカメラからのビデオフィードをライブ表示しています。 Xcodeの拡張現実アプリテンプレートとまったく同じようにARSCNViewオブジェクトを設定しています。カメラの視野を確保する方法はあるのでしょうか?
@IBOutlet var sceneView: ARSCNView!
func start() {
sceneView.delegate = self
sceneView.session.run(ARWorldTrackingConfiguration())
// Retrieve camera FOV here
}
ここに行くにはいくつかの方法があり、誤ったスタートをする可能性があります。
SceneKit(ARSCNView
)を介してすでにARKitを操作している場合、ARKitがSceneKitカメラを自動的に更新していると考えられるかもしれません(ビューの pointOfView
's- camera
)は、ARKitで使用される投影変換と一致します。これは正しいです。
ただし、ARKitはSCNCamera
の- projectionTransform
を直接設定します。 SCNCamera
およびzNear
および zFar
のようなfieldOfView
の幾何学的プロパティを操作する場合、SceneKitは、レンダリング。ただし、 projectionTransform
を直接設定した場合、near/far値とxFov/yFov値を復元できる数学はないため、対応するSCNCamera
プロパティは無効です。つまり、_sceneView.pointOfView.camera.fieldOfView
_および同様のAPIは、ARKitアプリに対して常に偽の結果を返します。
では、代わりに何ができますか?読む...
ARセッションは、デリゲートを通じて継続的に ARFrame
オブジェクトを販売します。または、そこから currentFrame
を要求できます。各フレームには、イメージングパラメータを説明する ARCamera
が付加されています。そのうちの1つは、視野に依存する projectionMatrix
です。 (同じマトリックスである前述のSceneKit projectionTransform
もあります。)
標準の3D射影行列には、垂直視野と縦横比に基づくスケーリング項が含まれています。具体的には、マトリックスは次のようになります。
_[ xScale 0 0 0 ] xScale = yScale * aspectRatio (width/height)
[ 0 yScale 0 0 ] yScale = 1 / tan(yFov/2)
[ 0 0 nf1 nf2 ] nf1 and nf2 relate to near and far clip planes,
[ 0 0 -1 0 ] so aren't relevant to field of view
_
したがって、yFov
方程式を解くことでyScale
を取得できるはずです。
_let projection = session.currentFrame!.camera.projectionMatrix
let yScale = projection[1,1]
let yFov = 2 * atan(1/yScale) // in radians
let yFovDegrees = yFov * 180/Float.pi
_
水平視野の場合は、アスペクト比(具体的には、幅/高さの比率)を掛けることができます。
_let imageResolution = session.currentFrame!.camera.imageResolution
let xFov = yFov * Float(imageResolution.width / imageResolution.height)
_
注:ここで、「水平」および「垂直」はカメラの画像を基準にしています。これは、デバイスまたはARの方法に関係なく、本来は横向きです。ビューのUIは指向的です。
ただし、よく見ると、ここのxFov
/yFov
のアスペクト比(およびimageResolution
のアスペクト比)は、必ずしもデバイスの画面(特にiPhone X)またはARコンテンツを描画しているビュー。これは、FOVの角度カメラの画像のを測定したためであり、アプリのARビューの角度ではありません。心配しないでください。そのためのAPIもあります...
ARCamera
は、射影行列を取得するための2つのAPIを提供します。先ほど説明したものの他に、プレゼンテーションを考慮に入れる projectionMatrix(for:viewportSize:zNear:zFar:)
もあります。カメラのFOVではなく、ARSCNView
またはARSKView
(またはUnityまたはUnrealのいずれか)がARシーンをレンダリングする方法のFOVを一致させる場合は、これを使用してデバイスを渡します向きとあなたの見方を見る。次に、上記と同じ計算をすべて実行します。
_let imageResolution = session.currentFrame!.camera.imageResolution
let viewSize = sceneView.bounds.size
let projection = session.currentFrame!.camera.projectionMatrix(for: .portrait,
viewportSize: viewSize, zNear: zNear, zFar: zFar)
let yScale = projection[1,1] // = 1/tan(fovy/2)
let yFovDegrees = 2 * atan(1/yScale) * 180/Float.pi
let xFovDegrees = yFovDegrees * Float(viewSize.height / viewSize.width)
_
zNear
とzFar
に何を渡してもかまいません。これに依存するマトリックスの部分を使用していないためです。 (_zNear < zFar
_および_zNear != zFar != 0
_を確認する必要がある場合もあります。)
注:これで高さ/幅はビュー(またはむしろ、
projectionMatrix(for:...)
に渡すビューの属性)に基づいています)。この例では、方向がyFov
であるため、portrait
はUIに対して垂直です。したがって、高さ/幅のアスペクト比を掛けてxFov
を取得します。横向きの場合は、代わりに幅/高さを掛けます。
熱心な観察者は、上記の計算では射影行列の一部が無視されることに気づいたかもしれません。 FOV角度の定義 はカメラの光学的特性であり、3D投影とは関係がないため、投影行列全体は中間結果であり、実際には必要ない場合があります。
ARCamera
は、カメラの光学特性を説明する intrinsics
マトリックスも公開します。この行列の対角線に沿った最初と2番目の値は、カメラ画像の単一ピクセルの水平方向と垂直方向 焦点距離 です。焦点距離と画像の幅/高さがある場合、 FOV角度の定義 に従ってFOVを計算できます。
_let imageResolution = session.currentFrame!.camera.imageResolution
let intrinsics = session.currentFrame!.camera.intrinsics
let xFovDegrees = 2 * atan(Float(imageResolution.width)/(2 * intrinsics[0,0])) * 180/Float.pi
let yFovDegrees = 2 * atan(Float(imageResolution.height)/(2 * intrinsics[1,1])) * 180/Float.pi
_
注:
projectionMatrix
を使用するバージョンと同様に、これはcameraのサイズと常に横向きに基づいていますimage、デバイス画面またはARコンテンツを表示しているビューではありません。代わりにビューポートに基づいて何かが必要な場合は、「ビューポートを使用した投影マトリックス」まで上にスクロールしてください。