4

I'm trying to reverse-engineer ARCamera's projectionMatrix(for:viewportSize:zNear:zFar:), but I'm getting wrong values for m[2][0] and m[2][1] (column-major). Here's what I got so far (I'm using landscapeRight orientation):

// intrinsics:
//   933.9137        0.0   617.7059
//        0.0   933.9137   363.0624
//        0.0        0.0        1.0
//
// viewportSize:
//   width: 700.0, height: 300.0
//
// imageSize (obtained from ARKit's camera):
//   width: 1280.0, height: 720.0
//
// zNear: 0.007, zFar: 1300.0
//
// Calculated matrix:
//   1.4592402         0.0   0.034834575            0.0
//         0.0   3.4048939   0.034834575            0.0
//         0.0         0.0    -1.0000054   -0.007000038
//         0.0         0.0          -1.0            0.0
//
// Expected matrix from projectionMatrix(for:viewportSize:zNear:zFar:):
//   1.4592401         0.0   0.034053326           0.0
//         0.0   3.4048936   0.012987971           0.0
//         0.0         0.0    -1.0000054  -0.007000038
//         0.0         0.0          -1.0           0.0

func calculateProjectionMatrix(intrinsics: simd_float3x3,
                               viewportSize: Size,
                               imageSize: Size,
                               zNear: Float,
                               zFar: Float) -> simd_float4x4 {

    let aspect = viewportSize.height / viewportSize.width
    let right: Float = imageSize.width - intrinsics[2][0]
    let left: Float = -intrinsics[2][0]
    let top: Float = right * aspect
    let bottom: Float = left * aspect

    return simd_float4x4(
        simd_float4(2 * intrinsics[0][0] / (right - left), 0, 0, 0),
        simd_float4(0, 2 * intrinsics[1][1] / (top - bottom), 0, 0),
        simd_float4((right + left) / (right - left), (top + bottom) / (top - bottom), -zFar / (zFar - zNear), -1.0),
        simd_float4(0, 0, -zFar * zNear / (zFar - zNear), 0)
    )
}

It seems that I'm not setting left, right, top, and bottom correctly. I know I ignored intrinsics[2][1], which I probably shouldn't, but even the result that depended only on right and left (m[2][0]) is wrong.

I read some blog posts (e.g., 1, 2) about this (most of them about OpenGL) but I couldn't get the exact matrix given by this method. Do you have any thoughts of what's wrong with my implementation and what should I do to get the same results as ARKit's function?

Marcel Alves
  • 486
  • 1
  • 8
  • 15
  • 1
    Possible duplicate of https://stackoverflow.com/questions/47536580/get-camera-field-of-view-in-ios-11-arkit – Softlion Oct 05 '20 at 07:51
  • I wouldn’t say it’s a duplicate exactly but the answer you linked brings a lot of useful information to answer my question. Thank you a lot. I’m going to check it carefully later today (because right now I’m on my cellphone). – Marcel Alves Oct 06 '20 at 12:48
  • I trying to solve this same problem. Did you ever find a solution? – Ryan Burgoyne Apr 11 '22 at 22:59

0 Answers0