确定 SKNode 是否在相机视图前面 (ARKit Spritekit)

Determine if SKNode is in front of camera view (ARKit Spritekit)

我正在尝试检测相机何时正对着我放置在 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
    }

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

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

我看了一段时间,得出的结论是试图获得 currentFrame.cameraanchor 之间的距离是行不通的,因为它 returns 相似的值,无论 anchor 是在相机前面还是后面。我的意思是,如果我们假设我们的锚点在 x 点,并且我们向前移动 1 米或向后移动 1 米,那么相机和锚点的距离仍然是 1 米。

因此,经过一些实验后,我认为我们需要查看以下 variablesfunctions 来帮助我们检测我们的 SKNode 是否在镜头前:

(a) SpriteNode的zPosition指的是:

The z-order of the node (used for ordering). Negative z is "into" the screen, Positive z is "out" of the screen

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

Returns true if the bounds of this node intersects with the transformed bounds of the other node, otherwise 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")
            }

        }
    }
}

希望对您有所帮助...

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

- (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.
 }