Реализация точки Unproject возвращает неправильные значения x - PullRequest
0 голосов
/ 23 сентября 2019

Я работаю над проектом IOS с ARKit, в котором я пытаюсь получить мировую координату (3D) из экранной 2D-координаты.Я знаю, что мы можем легко получить это, используя непроектированную функцию SCNView или ARSCNView.но по некоторым другим причинам мне нужно получить координаты мира, используя только ARCamera и Screen Coordinates.Из интернета я нашел некоторые решения о том, как получить мировые координаты, используя матрицы просмотра и проекции камеры и точки экрана.Я почти близок к решению, но по какой-то причине значение X имеет некоторое смещение.

Ниже приведена реализация функции Unproject, которую я использую с https://stackoverflow.com/a/47897206/9719840

func unproject(screenPoint: float3, // see below for Z depth hint discussion
        modelView: float4x4,
        projection: float4x4,
        viewport: CGRect) -> float3 {



        // viewport to clip: subtract viewport origin, divide by size,
        // scale/offset from 0...1 to -1...1 coordinate space
        var clip = (screenPoint - float3(Float(viewport.minX), Float(viewport.minY), 1.0))
            / float3(Float(viewport.width), Float(viewport.height), 1.0)
            * float3(repeating: 2)


        clip = float3.init(clip.y - 1, clip.x - 1 , clip.z - 1)
        print("clip: \(clip)")
        // apply the reverse of the model-view-projection transform
        let inversePM = (projection * modelView).inverse
        let result = inversePM * float4(clip.x, clip.y, clip.z, 1.0)
        return float3(result.x, result.y, result.z) / result.w // perspective divide
    }

И вот как я вызываю вышеуказанную функцию


func screenToWorld(from point: CGPoint, camera:ARCamera){



        let farPoint = unproject(screenPoint: float3.init(Float(point.x), Float(point.y), 1), modelView: camera.transform.inverse, projection: camera.projectionMatrix, viewport: self.arView.frame) 

        let nearPoint = unproject(screenPoint: float3.init(Float(point.x), Float(point.y), 0), modelView: camera.transform.inverse, projection: camera.projectionMatrix, viewport: self.arView.frame)

        var worldPoint = SCNVector3(farPoint.x - nearPoint.x,  farPoint.y - nearPoint.y, farPoint.z - nearPoint.z).normalized()


       let camPos = lastFrame.camera.transform * float4(x: 0, y: 0, z: 0, w: 1)
         let camPosition = SCNVector3(camPos.x, camPos.y, camPos.z)


        //add campos to the result
        worldPoint = SCNVector3(worldPoint.x + camPosition.x , worldPoint.y + camPosition.y , worldPoint.z + camPosition.z )






        // adding a cube at the tapped position for debugging    

        let anchor = ARAnchor.init(name: "str", transform: float4x4(float4(1, 0, 0, 0),
                                                                    float4(0, 1, 0, 0),
                                                                    float4(0, 0, 1, 0),
                                                                    float4(worldPoint.x,
                                                                           worldPoint.y,
                                                                           worldPoint.z,
                                                                           1)))

        self.arView.session.add(anchor: anchor)

        }

   }
 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {


        guard let touch = touches.first else { return }
        let touchPoint = touch.location(in: self.arView)

        if let frame = arView.session.currentFrame{
            initPoint = touchPoint
            savedFrame = frame
            screenToWorld(from: touchPoint, camera: frame.camera)
        }

    }

Используя приведенный выше код, я могу размещать кубы там, где я касаюсь экрана, но есть некоторое смещение / смещение в позиции x.(например, если я коснусь рядом с центром, куб будет располагаться хорошо, но если я поставлю его рядом с углами, он будет расположен немного дальше вдоль оси x)

...