Matrix 将屏幕点取消投影到ARKit中的水平面

Matrix 将屏幕点取消投影到ARKit中的水平面,matrix,opengl-es,augmented-reality,arkit,metal,Matrix,Opengl Es,Augmented Reality,Arkit,Metal,我正在尝试使用ARKit将屏幕上的某个点投影到世界空间中ARPlaneAnchor上的坐标。基本上,我想根据相机的指向在地平面上画一个标记。ARKit提供了一些方法来实现这一点,但是它们附加到ARCamera类,不幸的是,在我的场景中,我只能访问相机的投影、视图和变换矩阵,而没有参考ARFrame或ARCamera对象本身。我写了一些与glunproject()类似的东西(据我所知) 屏幕点是一些窗口坐标 通过在前面的过程中从深度缓冲区读回值来计算深度 screenSize是视口的大小 投影矩阵

我正在尝试使用ARKit将屏幕上的某个点投影到世界空间中ARPlaneAnchor上的坐标。基本上,我想根据相机的指向在地平面上画一个标记。ARKit提供了一些方法来实现这一点,但是它们附加到ARCamera类,不幸的是,在我的场景中,我只能访问相机的投影、视图和变换矩阵,而没有参考ARFrame或ARCamera对象本身。我写了一些与glunproject()类似的东西(据我所知)

  • 屏幕点是一些窗口坐标
  • 通过在前面的过程中从深度缓冲区读回值来计算深度
  • screenSize是视口的大小
  • 投影矩阵来自
  • viewMatrix来自
  • 我唯一不确定的是viewMatrix属性。我唯一能想到的是相机上的变换矩阵。然而,我试过这个,它似乎也没有给我正确的位置。在GlunProject中,他们称这个值为modelView矩阵,在glm中,它只是称为model,所以我对它应该是什么有点困惑

    用我从非投影函数中得到的值,我像这样翻译一个单位矩阵

    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) 
    
    我认为我的z值是正确的(深度缓冲区中的深度值),所以实际上我只需要找到我的x和y。我也不能100%确定如何处理unproject函数返回的值。我假设这只是世界坐标,但可能需要以某种方式进行缩放


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

    对于将来遇到此问题的任何人来说,解决方案(如@rabbi76所建议的)是翻转投影矩阵和视图矩阵以及逆矩阵和输入点的乘法顺序。我还需要翻转我想要检查的屏幕点的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)
    }
    

    它必须是
    viewProj=projectionMatrix*viewMatrix
    position=inverse*inPoint
    Aha!我想这就成功了。离得这么近很痛苦,但…对我来说不起作用,如果我找到原因,我会回来的
    VertexOut vertexOut;
    float4x4 modelViewMatrix = viewMatrix * modelMatrix;
    vertexOut.position = projectionMatrix * modelViewMatrix * vertexIn.position;
    return vertexOut;
    
    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)
    }