确定SKNode是否在摄影机视图之前(ARKit Spritekit)

时间:2018-10-15 21:26:01

标签: ios swift sprite-kit arkit

我正在尝试检测相机何时面对放置在ARSKView中的物体。这是代码:

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        guard let sceneView = self.view as? ARSKView else {
            return
        }

        if let currentFrame = sceneView.session.currentFrame {
            //let cameraZ =  currentFrame.camera.transform.columns.3.z
            for anchor in currentFrame.anchors {
                if let spriteNode = sceneView.node(for: anchor), spriteNode.name == "token", intersects(spriteNode) {
                    // token is within the camera view
                    let distance = simd_distance(anchor.transform.columns.3,
                                                 currentFrame.camera.transform.columns.3)
                    //print("DISTANCE BETWEEN CAMERA AND TOKEN: \(distance)")
                    if distance <= captureDistance {
                        // token is within the camera view and within capture distance
                        print("token is within the camera view and within capture distance")
                    }
                }
            }
        }
    }

问题在于,当对象直接位于相机的前面和后面时,intersects方法都返回true。如何更新此代码,使其仅检测spriteNode在当前相机取景器中的时间?顺便说一下,我正在使用SpriteKit,而不是SceneKit。

这是我用来实际创建锚点的代码:

        self.captureDistance = captureDistance
        guard let sceneView = self.view as? ARSKView else {
            return
        }

        // Create anchor using the camera's current position
        if sceneView.session.currentFrame != nil {

            print("token dropped at \(distance) meters and bearing: \(bearing)")

            // Add a new anchor to the session
            let transform = getTransformGiven(bearing: bearing, distance: distance)
            let anchor = ARAnchor(transform: transform)
            sceneView.session.add(anchor: anchor)
        }

        func getTransformGiven(bearing: Float, distance: Float) -> matrix_float4x4 {
        let origin = MatrixHelper.translate(x: 0, y: 0, z: Float(distance * -1))
        let bearingTransform = MatrixHelper.rotateMatrixAroundY(degrees: bearing * -1, matrix: origin)
        return bearingTransform
    }

3 个答案:

答案 0 :(得分:1)

我花了一段时间研究得出的结论是,试图获得currentFrame.cameraanchor之间的距离并不能简单地因为它返回相似的值而与anchor是在摄像机的前面还是后面。我的意思是,假设我们的锚点位于x点,并且向前移动1米或向后移动1米,则距摄像机和锚点的距离仍为1米。

这样,经过一些试验,我相信我们需要查看以下variablesfunctions来帮助我们检测我们的SKNode是否在镜头前:

(a)SpriteNode的zPosition指向:

  

节点的z顺序(用于排序)。负数z是“插入”屏幕,正数z是“移出”屏幕

(b)open func intersects(_ node: SKNode) -> Bool其中:

  

如果此节点的边界与边界相交,则返回true。   另一个节点的转换边界,否则为false。

因此,以下内容似乎可以完全满足您的需求:

override func update(_ currentTime: TimeInterval) {

    //1. Get The Current ARSKView & Current Frame
    guard let sceneView = self.view as? ARSKView, let currentFrame = sceneView.session.currentFrame else { return }

    //3. Iterate Through Our Anchors & Check For Our Token Node
    for anchor in currentFrame.anchors {

        if let spriteNode = sceneView.node(for: anchor),  spriteNode.name == "token"{

            /*
             If The ZPosition Of The SpriteNode Is Negative It Can Be Seen As Into The Screen Whereas Positive Is Out Of The Screen
             However We Also Need To Know Whether The Actual Frostrum (SKScene) Intersects Our Object
             If Our ZPosition Is Negative & The SKScene Doesnt Intersect Our Node Then We Can Assume It Isnt Visible
            */

            if spriteNode.zPosition <= 0 && intersects(spriteNode){
                print("Infront Of Camera")
            }else{
                print("Not InFront Of Camera")
            }

        }
    }
}

希望有帮助...

答案 1 :(得分:1)

您也可以使用此功能检查相机的位置:-

- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame; {

       simd_float4x4 transform = session.currentFrame.camera.transform;

       SCNVector3 position = SCNVector3Make(transform.columns[3].x,
                                         transform.columns[3].y,
                                         transform.columns[3].z);

       // Call any function to check the Position.
 }

答案 2 :(得分:0)

我会给你一个线索。像这样检查ZPosition。

    if let spriteNode = sceneView.node(for: anchor), 
       spriteNode.name == "token", 
       intersects(spriteNode) && spriteNode.zPosition < 0 {....}