Search code examples
swiftaugmented-realityscenekitarkitrealitykit

Visualize a placement point on a surface in AR app


I would like to draw a Focus Circle and a shadow inside it on a plane beneath the object I'm placing to, like in IKEA AR application.

How do I do that?

enter image description here


Solution

  • SceneKit solution

    To create a Focus Circle, like in Ikea AR app, I recommend you use a png file with a premultiplied RGBA channels like this one (drag-and-drop it on your Desktop for testing)


    enter image description here


    import SceneKit
    
    let scene = SCNScene(named: "chair.scn")!
    let sceneView = self.view as! SCNView
    sceneView.scene = scene
    sceneView.allowsCameraControl = true
    sceneView.backgroundColor = .black
        
    

    let focusCircle = SCNNode()
    focusCircle.geometry = SCNPlane(width: 1.0, height: 1.0)
    focusCircle.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "crcl")
    focusCircle.position.y = 0.01
    focusCircle.eulerAngles.x = -.pi/2
    scene.rootNode.addChildNode(focusCircle)
    

    let actionA = SCNAction.scale(to: 0.1, duration: 0.5)
    let actionB = SCNAction.scale(to: 0.9, duration: 0.5)
    let sequence = SCNAction.sequence([actionA, actionB])
    focusCircle.runAction(SCNAction.repeatForever(sequence))
    

    enter image description here

    For generating a shadow you need to add a directional light in your scene. Here's the code:

    let sun = SCNNode()
    sun.light = SCNLight()
    sun.light!.type = .directional
    sun.light!.castsShadow = true
    sun.light!.shadowMode = .deferred
    sun.light!.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
    sun.rotation = SCNVector4(x: -1, y: 0, z: 0, w: .pi/2)
    scene.rootNode.addChildNode(sun)
    

    Then you need to create an invisible plane for your semi-transparent shadow:

    let shadowPlane = SCNNode()
    shadowPlane.geometry = SCNFloor()
    shadowPlane.geometry?.firstMaterial!.colorBufferWriteMask = []
    shadowPlane.geometry?.firstMaterial!.readsFromDepthBuffer = true
    shadowPlane.geometry?.firstMaterial!.writesToDepthBuffer = true
    shadowPlane.geometry?.firstMaterial!.lightingModel = .shadowOnly
    scene.rootNode.addChildNode(shadowPlane)
    


    RealityKit solution

    Using the RealityKit SDK to create a Focus Circle is even easier because the framework has a VideoMaterial. Read this post to find out how to implement RealityKit's video material to a plane.