'Converting worldPosition into a SceneView position with SceneKit/Swift

iOS 15, Swift 5

I am trying to get sceneView [SwiftUI SceneKit plugin] to work with adding/finding nodes within my scene. And I feel I am almost there and yet I am not.

Sadly the hits function here finds nothing, which is why I ended up commenting it out. I tried used projectPoint after that, but the results make no sense?

Now I did get this working using UIViewRespresentable, but that solution doesn't use sceneView at all.

I want to convert the drag coordinates to the SCNView coordinates since since I think I can find/match objects.

import SwiftUI
import SceneKit

struct ContentView: View {

let settings = SharedView.shared
var (scene,cameraNode) = GameScene.shared.makeView()

var body: some View {
    GameView(scene: scene, cameraNode: cameraNode)
}
}

struct GameView: View {
let settings = SharedView.shared
@State var scene: SCNScene
@State var cameraNode: SCNNode

var body: some View {
    SceneView(
                scene: scene,
                pointOfView: cameraNode,
                options: [.autoenablesDefaultLighting, .rendersContinuously ], delegate: SceneDelegate())
        .gesture(DragGesture(minimumDistance: 0)
                    .onChanged({ gesture in
            settings.location = gesture.location
        }).sequenced(before: TapGesture().onEnded({ _ in
            GameScene.shared.tapV()
        }))
        )
}
}

class SharedView: ObservableObject {
@Published var location:CGPoint!
@Published var view:UIView!
@Published var scene:SCNScene!
@Published var sphereNode:SCNNode!
static var shared = SharedView()
}

@MainActor class SceneDelegate: NSObject, SCNSceneRendererDelegate {
}


class GameScene: UIView {
static var shared = GameScene()
let settings = SharedView.shared
var view: SCNView!
var scene: SCNScene!

func makeView() -> (SCNScene,SCNNode) {
    
    let material = SCNMaterial()
    material.diffuse.contents = UIColor.red
    let sphere = SCNSphere(radius: 1.0)
    sphere.materials = [material]
    let sphereNode = SCNNode()
    sphereNode.geometry = sphere
    sphere.name = "sphereNode"
    let camera = SCNCamera()
    camera.fieldOfView = 90.0
    let light = SCNLight()
    light.color = UIColor.white
    light.type = .omni
    let cameraNode = SCNNode()
    cameraNode.simdPosition = SIMD3<Float>(0.0, 0.0, 6)
    cameraNode.camera = camera
    cameraNode.light = light
    
    scene = SCNScene()
    scene.background.contents = UIColor.black
    scene.rootNode.addChildNode(sphereNode)
    scene.rootNode.addChildNode(cameraNode)
    
    view = SCNView()
    view.scene = scene
    view.pointOfView = cameraNode
    settings.sphereNode = sphereNode
    
    return (scene, cameraNode)
  }

func tapV() {

    let location = settings.location
    let hits = view.hitTest(location!, options: [.boundingBoxOnly: true, .firstFoundOnly: true, .searchMode: true])
    print("hits \(hits.count)")
    
//  for hit in hits {
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.yellow
        let geometry = SCNSphere(radius: 0.1)
        geometry.materials = [material]
        let node = SCNNode()
        node.geometry = geometry
       // node.simdPosition = hit.simdWorldCoordinates
        let projectedOrigin = view.projectPoint(SCNVector3Zero)
        var worldPoint = view.unprojectPoint(SCNVector3(location!.x, location!.y, CGFloat(0)))
 

        node.worldPosition = worldPoint
        view.scene!.rootNode.addChildNode(node)
        print("node \(node.position) \(hits.count)")
//    }
  }

  }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source