Using SceneKit for hitTesting not returning a hit with SCNNode

自作多情 提交于 2020-01-05 02:30:36

问题


The documentation in XCode clearly states that hitTesting a geometry in SceneKit can be done with SCNRender, SCNView or the SCNNode themselves when one plans to test a 3D line segment. I have a use for SCNScene with its nodes without a renderer or a view, therefore I am planning to use SCNNode hitTesting. I create a SCNScene, put a SCNNode in it and test a simple ray that goes through, but I always get an empty hitList and I don't understand why:

import Swift
import SceneKit

let boxGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0)
let boxNode = SCNNode(geometry: boxGeometry)

var scene = SCNScene()
scene.rootNode.addChildNode(boxNode)

let from = SCNVector3(x: 0, y: -2, z: 0)
let to = SCNVector3(x: 0, y: 2 , z: 0)

var hits = scene.rootNode.hitTestWithSegmentFromPoint(from, toPoint: to, options:nil) // this is always empty
if hits != nil {
    if hits!.count > 0 {
        var hit = (hits!.first as! SCNHitTestResult).node as SCNNode
    }
}

I have tried passing various forms of options but nothing changes.

  1. SCNHitTestFirstFoundOnlyKey: yes or no does not change anything
  2. SCNHitTestSortResultsKey: yes or no does not change anything
  3. SCNHitTestClipToZRangeKey: invalid for SCNNode
  4. SCNHitTestBackFaceCullingKey: yes or no does not change anything
  5. SCNHitTestBoundingBoxOnlyKey: yes or no does not change anything
  6. SCNHitTestRootNodeKey: rootNOde of scene or boxNode does not change anything
  7. SCNHitTestIgnoreHiddenNodesKey: yes or no does not change anything

What am I doing wrong?


回答1:


I have found the answer, which is either a bug or a feature: using SCNScene and its nodes SCNNode for 3D hitTesting, in particular the method: "hitTestWithSegmentFromPoint(toPoint:options:)" does not return a hit unless the scene is included in an SCNView. It appears it cannot be used offscreen. My guess is yours for why this is the case, although I can imagine it has something to do with performing some of these quite expensive calculations on the graphics card.

I have tested this using the GameView SCNScene starter project. The critical line is self.gameView!.scene = scene

override func awakeFromNib(){
    let scene = SCNScene()
    let boxGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0)
    let boxNode = SCNNode(geometry: boxGeometry)
    boxNode.position=SCNVector3(x: 0, y: 0, z: 0)
    scene.rootNode.addChildNode(boxNode)

    // create and add a camera to the scene
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    scene.rootNode.addChildNode(cameraNode)

    // place the camera
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

    // create and add a light to the scene
    let lightNode = SCNNode()
    lightNode.light = SCNLight()
    lightNode.light!.type = SCNLightTypeOmni
    lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
    scene.rootNode.addChildNode(lightNode)

    // create and add an ambient light to the scene
    let ambientLightNode = SCNNode()
    ambientLightNode.light = SCNLight()
    ambientLightNode.light!.type = SCNLightTypeAmbient
    ambientLightNode.light!.color = NSColor.darkGrayColor()
    scene.rootNode.addChildNode(ambientLightNode)

    // set the scene to the view
    // uncomment this to fail
    self.gameView!.scene = scene

    // allows the user to manipulate the camera
    self.gameView!.allowsCameraControl = true

    // show statistics such as fps and timing information
    self.gameView!.showsStatistics = true

    // configure the view
    self.gameView!.backgroundColor = NSColor.blackColor()

    let hitList = scene.rootNode.hitTestWithSegmentFromPoint(SCNVector3(x:-10,y:0,z:0), toPoint: SCNVector3(x:10,y:0,z:0), options:[SCNHitTestBackFaceCullingKey:false, SCNHitTestSortResultsKey:true, SCNHitTestIgnoreHiddenNodesKey:false])

    if hitList?.count > 0 {
        println("Hit found: \n\n\( hitList![0] )") // assign self.gameView!.scene = scene to reach this point.
    } else {
        println("No hit") // uncomment self.gameView!.scene = scene to reach this point.
    }

}



回答2:


I've also had trouble with hitTestWithSegmentFromPoint.

I was calling it in viewDidLoad() and it returned a 0 elements array, though I was sure there was a hit.

Calling it in viewDidAppear() (or later) solved my problem.



来源:https://stackoverflow.com/questions/29198636/using-scenekit-for-hittesting-not-returning-a-hit-with-scnnode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!