matrix - 在 ARKit 中将屏幕点取消投影到水平面

标签 matrix opengl-es augmented-reality arkit metal

我正在尝试使用 ARKit 将屏幕上的某个点取消投影到世界空间中 ARPlaneAnchor 上的坐标。本质上,我想根据相机指向的位置在地平面上绘制一个标记。 ARKit 提供了一些方法来做到这一点,但是它们附加到 ARCamera 类,不幸的是,在我的场景中,我只能访问相机的投影、 View 和变换矩阵,并且没有引用 ARFrame 或 ARCamera 对象本身。我写了一些与 gluUnproject() 类似的东西(据我所知)。

func screenToWorld(screenPoint: CGPoint, depth: Float, screenSize: CGSize, projectionMatrix: simd_float4x4, viewMatrix:simd_float4x4) -> float3{

    let viewProj = viewMatrix * projectionMatrix
    let inverse = simd_inverse(viewProj)

    let x = (2.0 * screenPoint.x ) / screenSize.width - 1.0
    let y = (2.0 * screenPoint.y) / screenSize.height - 1.0

    let inPoint = float4(Float(x), Float(y), depth * 2.0 - 1.0, 1.0)

    var position = inPoint * inverse
    position.w = 1.0 / position.w

    position.x *= position.w
    position.y *= position.w
    position.z *= position.w

    return float3(position.x, position.y, position.z)
}


let pos = screenToWorld(screenPoint: CGPoint(360, 640), depth: depthBufferValue, screenSize: CGSize(720, 1280), projectionMatrix: projectionMatrix, viewMatrix: viewMatrix)
  • screenPoint 是某个窗口坐标
  • 深度是通过在较早的 channel 中读回深度缓冲区中的值来计算的
  • screenSize 是视口(viewport)的大小
  • projectionMatrix 来自 projectionMatrix(for:.portrait, viewportSize: CGSize(720,1280),zNear: 0.001, zFar: 1000)
  • viewMatrix 来自 viewMatrix(for:.portrait)

  • 我唯一不确定的是 viewMatrix 属性。我唯一能想到的可能是附加到相机的变换矩阵。但是,我已经尝试过了,它似乎也没有给我正确的位置。在 gluUnproject 他们将此值称为模型 View 矩阵,在 glm 中它只是称为模型,所以我对这应该是什么感到有点困惑。

    使用从我的 unProject 函数中获得的值,我可以像这样转换一个单位矩阵
    var modelMatrix = matrix_identity_float4x4
    modelMatrix = modelMatrix.translatedBy(x: pos.x, y: pos.y, z: pos.z)
    

    然后像这样将值发送到着色器......
    encoder.setVertexBytes(&projectionMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 1)
    encoder.setVertexBytes(&viewMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 2)
    encoder.setVertexBytes(&modelMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 3) 
    

    在我的顶点着色器里面我做
    VertexOut vertexOut;
    float4x4 modelViewMatrix = viewMatrix * modelMatrix;
    vertexOut.position = projectionMatrix * modelViewMatrix * vertexIn.position;
    return vertexOut;
    

    我认为我的 z 值是正确的(深度缓冲区中的深度值),所以实际上我只需要找到我的 x 和 y。我也不是 100% 确定如何处理我的 unproject 函数返回的值。我认为这只是世界坐标,但也许需要以某种方式缩放?

    我很想得到一些帮助来获得正确的坐标,或者如果上面有任何错误,请指出!

    最佳答案

    对于将来遇到此问题的任何人,解决方案(如@rabbid76 所建议的)正在翻转我的投影和 View 矩阵以及我的逆矩阵和 inPoint 的乘法顺序。我还需要翻转要检查的 screenPoint 的 y 坐标。

    这是完整的功能:

    func screenToWorld(screenPoint: CGPoint, depth: Float, screenSize: CGSize, projectionMatrix: simd_float4x4, viewMatrix:simd_float4x4) -> float3{
    
        let viewProj = projectionMatrix * viewMatrix
        let inverse = simd_inverse(viewProj)
    
        let x = (2.0 * screenPoint.x ) / screenSize.width - 1.0
        let y = 1.0 - (2.0 * screenPoint.y) / screenSize.height 
    
        let inPoint = float4(Float(x), Float(y), depth * 2.0 - 1.0, 1.0)
    
        var position = inverse * inPoint
        position.w = 1.0 / position.w
    
        position.x *= position.w
        position.y *= position.w
        position.z *= position.w
    
        return float3(position.x, position.y, position.z)
    }
    

    关于matrix - 在 ARKit 中将屏幕点取消投影到水平面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52461052/

    相关文章:

    swift - LiDAR 和 RealityKit – 为扫描模型捕捉真实世界的纹理

    matrix - pandas - 针对所有其他行将函数应用于当前行

    r - 如何结合两个不均匀的数据框来创建一个完整的物种矩阵进行分析?

    matlab - 在matlab中逐列计算相关性的快速方法是什么

    android - 使用 OpenGL 更快的相机预览?

    iOS:使用哪种增强现实 SDK 用于虚拟试衣间?

    python - 给定转移概率矩阵,如何生成随机序列?

    ios - 如何使用 OpenGL ES 2.0 将巨大的数组传递给 iOS 上的着色器?

    java - 如何在 Android 上使用 OpenGL ES 扩展

    ios - Zxing示例中的条形码扫描仪