swiftscenekitscnnodescncamera

How to get localCoordinates and localNormal of point of mesh(SCNNode) SCNCamera is looking at?


I have a SCNScene. Inside it, I have a mesh (SCNNode) and another SCNNode with SCNCamera.

let sceneView = SCNView()
let scene = SCNScene()
let meshNode: SCNNode()
lazy var cameraNode: SCNNode = {
    let node = SCNNode()
    let camera = SCNCamera()
    node.camera = camera
    return node
}()

User can rotate the camera to see around. Whenever I want, I need to be able to get coordinates of point of mesh, the camera is looking at, and normal vector at this point.

I want to explain more simply. So imagine, the camera points a laser ray in front of itself (in the direction it looks). And this ray hit the mesh. I need the coordinates of this point (where the ray hit the mesh). And a normal vector at this point.

Basically, what I need is similar to information which SCNHitTestResult provides:

let hitResults = sceneView.hitTest(touchPoint, options: [:])
if let result: SCNHitTestResult = hitResults.first {
    let localCoordinates = result.localCoordinates
    let localNormal = result.localNormal
}

How can I get localCoordinates and localNormal of a point on the mesh the camera is looking at?

Solved!

with the help of @mnuages and this answer https://stackoverflow.com/a/42034883/19433422 I solved problem:

func sceneSpacePosition(inFrontOf node: SCNNode, atDistance distance: Float) -> SCNVector3 {
    let localPosition = SCNVector3(x: 0, y: 0, z: Float(CGFloat(-distance)))
    let scenePosition = node.convertPosition(localPosition, to: nil)
    return scenePosition
}

let to: SCNVector3 = sceneSpacePosition(inFrontOf: cameraNode, atDistance: Float(radius))

if let hitTest = scene.rootNode.hitTestWithSegment(from: cameraNode.position, to: to, options: .none).first {
    let localCoordinates = hitTest.localCoordinates
    let localNormal = hitTest.localNormal
}

Solution

  • You can use [SCNNode hitTestWithSegmentFromPoint:toPoint:options:] to achieve that.

    Alternatively, if the camera is the current point of view then a hit test at the middle of the SCNView achieves what you want.