【问题标题】:Method "isNode(:insideFrustumOf:)" always true方法“isNode(:insideFrustumOf:)”始终为真
【发布时间】:2018-04-17 09:43:20
【问题描述】:

我正在尝试验证特定节点是否在场景的当前截锥体内。 因此我使用 Apple 的方法isNode(_:insideFrustumOf:)。 我在每次调用 renderer(_:didAdd:for:) 时保存相应的节点,然后使用 isNode(_:insideFrustumOf:) 进行测试。

但结果总是正确的,这显然是错误的。

为什么我不能测试 ARKit 添加的节点?

更新: 询问的代码,如果有帮助,太好了!

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    //...
        nodes.append(node)
    //...
}

nodes 是一个 SCNNodes 数组。

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        for node in nodes {
            let result = sceneView.isNode(node, insideFrustumOf: sceneView.pointOfView!)
            //...
        }
}

在这里进行节点的评估。结果总是正确的。

【问题讨论】:

  • 您需要发布一些实际代码让我们帮助您:)
  • 我做了,希望对你有帮助

标签: ios swift scenekit arkit


【解决方案1】:

由于您尚未发布所有代码,因此很难提供“明确”的答案。

话虽如此,我已经为您创建了一个效果很好的示例。

首先我创建了一个[SCNNode] 来存储添加到屏幕上的任何SCNNodes

 //Array To Store Any Added Nodes To The Scene Hierachy
 var nodesRendered = [SCNNode]()

然后我创建了 3 个不同的SCNNodes

/// Creates A Red, Blue & Green SCNNode
func createNodes(){

    //1. Create A Red Sphere
    let redNode = SCNNode()
    let redGeometry = SCNSphere(radius: 0.2)
    redGeometry.firstMaterial?.diffuse.contents = UIColor.red
    redNode.geometry = redGeometry
    redNode.position = SCNVector3(-1.5, 0, -1.5)
    redNode.name = "RedNode"

    //2. Create A Green Sphere
    let greenNode = SCNNode()
    let greenGeometry = SCNSphere(radius: 0.2)
    greenGeometry.firstMaterial?.diffuse.contents = UIColor.green
    greenNode.geometry = greenGeometry
    greenNode.position = SCNVector3(0, 0, -1.5)
    greenNode.name = "GreenNode"

    //3. Create A Blue Sphere
    let blueNode = SCNNode()
    let blueGeometry = SCNSphere(radius: 0.2)
    blueGeometry.firstMaterial?.diffuse.contents = UIColor.blue
    blueNode.geometry = blueGeometry
    blueNode.position = SCNVector3(1.5, 0, -1.5)
    blueNode.name = "BlueNode"

    //4. Add Them To The Hierachy
    augmentedRealityView.scene.rootNode.addChildNode(redNode)
    augmentedRealityView.scene.rootNode.addChildNode(greenNode)
    augmentedRealityView.scene.rootNode.addChildNode(blueNode)

    //5. Store A Reference To The Nodes
    nodesRendered.append(redNode)
    nodesRendered.append(blueNode)
    nodesRendered.append(greenNode)
}

完成此操作后,我创建了一个函数来确定这些是否在相机的截锥体中:

/// Detects If A Node Is In View Of The Camera
func detectNodeInFrustrumOfCamera(){

    guard let cameraPointOfView = self.augmentedRealityView.pointOfView else { return }

    for node in nodesRendered{

        if augmentedRealityView.isNode(node, insideFrustumOf: cameraPointOfView){

            print("\(node.name!) Is In View Of Camera")

        }else{

            print("\(node.name!) Is Not In View Of Camera")
        }
    }

}

最后在delegate 回调中我这样调用函数:

 func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

        detectNodeInFrustrumOfCamera()

  }

产生如下结果:

RedNode 不在摄像头范围内

BlueNode 不在摄像头范围内

GreenNode 在摄像头的视野中

希望它为您指明正确的方向...

【讨论】:

  • 您正在做的是将 SCNNode 手动添加到场景中。但我的问题是来自 ARKit 的添加节点。 ARKit 自己在回调渲染器(_:didAdd:for:) 中添加节点(例如,用于平面检测)。所以我的理解是你手动做的,ARKit 自己做的,因此应该可以跟踪这些自动添加的 SCNNodes 吗?但这似乎对我不起作用。
【解决方案2】:

所以我自己在做一个 ARKit 项目时遇到了这个问题。对于 ARKit 自动添加的节点,函数 isNode(node:, insideFrustumOf:) 似乎总是返回 true。

我的解决方法不是尝试跟踪 ARKit 添加的节点,而是创建一个具有与检测到的对象具有相同“体积”的透明材质的新节点,然后创建一个引用并检查该节点是否在查看。

添加这些变量:

    /// The object that was detected.
    var refObject: ARReferenceObject?

    /// The reference node for the detected object.
    var refNode: SCNNode?

    /// additional node which we'll use to check the POV against.
    var detectionNode: SCNNode?

实现委托函数didAdd

public func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {


        if let objectAnchor = anchor as? ARObjectAnchor {

            guard let name = objectAnchor.referenceObject.name, name == "my_object" 
            else { return }
            print("detected object for the first time")


            // create geometry
            let cube = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.0)

            // apply transparent material
            let material = SCNMaterial()
            material.transparency = 0.0
            cube.firstMaterial = material

            // add child node
            let detectionNode = SCNNode(geometry: cube)
            node.addChildNode(detectionNode)

            // store references
            self.detectionNode = detectionNode // this is the reference we really need
            self.refNode = node
            self.refObject = objectAnchor.referenceObject


        }
    }

终于实现了这个委托函数updateAtTime

public func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        guard let node = self.detectionNode else { return }

        if let pointOfView = sceneView.pointOfView {
            let isVisible = sceneView.isNode(node, insideFrustumOf: pointOfView)
            print("Is node visible: \(isVisible)")
        }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 2015-12-05
    相关资源
    最近更新 更多